<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
  <channel>
    <title>JBake</title>
    <link>https://melix.github.io/blog/</link>
    <atom:link href="https://melix.github.io/blog//feed.xml" rel="self" type="application/rss+xml" />
    <description>JBake Bootstrap Template</description>
    <language>en-gb</language>
    <pubDate>Wed, 18 Feb 2026 23:01:34 +0100</pubDate>
    <lastBuildDate>Wed, 18 Feb 2026 23:01:34 +0100</lastBuildDate>

    <item>
      <title>Announcing TamboUI</title>
      <link>https://melix.github.io/blog//2026/02/17-announcing-tamboui.html</link>
      <pubDate>Tue, 17 Feb 2026 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2026/02/17-announcing-tamboui.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This blog post is co-authored by &lt;a href=&quot;https://melix.github.io/blog/2026/02/17-announcing-tamboui.html&quot;&gt;Cédric Champeau&lt;/a&gt; (Micronaut) and &lt;a href=&quot;https://xam.dk/blog/announcing-tamboui&quot;&gt;Max Rydahl Andersen&lt;/a&gt; (Quarkus), and cross-posted on our respective personal blogs.&lt;/p&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today we are excited to announce &lt;a href=&quot;https://tamboui.dev/&quot;&gt;TamboUI&lt;/a&gt;, an open-source Terminal UI framework for the Java ecosystem!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The terminal is having a renaissance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;AI coding tools live there. Developer workflows are increasingly CLI-first again. Rust has &lt;a href=&quot;https://ratatui.rs/&quot;&gt;Ratatui&lt;/a&gt;. Python has Rich and Textual, Go has Charm, Typescript has OpenTUI. But Java, despite its performance, maturity, and tooling, didn’t have a modern, composable, developer-friendly TUI framework.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We thought that should change.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;videoblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;iframe width=&quot;640&quot; height=&quot;480&quot; src=&quot;https://www.youtube.com/embed/ERAp2vRHX3M?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_it_started&quot;&gt;How it started&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;TamboUI (pronounced like the french word “tambouille”, slang for &quot;cooking up something&quot; or &quot;makeshift creation&quot;) was born a bit by accident: a couple months ago, Cédric was &lt;a href=&quot;https://bsky.app/profile/melix.champeau.me/post/3m7ulazaogt25&quot;&gt;asking about which TUI libraries that tools like Claude Code were using&lt;/a&gt;. Max Andersen answered that most likely this was &lt;a href=&quot;https://ratatui.rs/&quot;&gt;Ratatui&lt;/a&gt;, a framework written in Rust. Both thought that it was a bit sad that there was no such library for Java.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A few weeks later, &lt;a href=&quot;https://bsky.app/profile/melix.champeau.me/post/3mae3pyw4ek25&quot;&gt;Cédric did an experiment by asking AI (Claude Code) to port Ratatui to Java&lt;/a&gt;. The result was fairly impressive, and the beginning of a collaboration that led to the creation of TamboUI. In fact, Max &lt;a href=&quot;https://xam.dk/blog/lets-make-2026-the-year-of-java-in-the-terminal/&quot;&gt;gave you a hint last year&lt;/a&gt; that this was going to happen.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That said, TamboUI is not a Ratatui port nor is it a Textual port. We’ve put a lot of effort in going beyond the initial AI generated port. The library was designed with Java developers in mind, inspired by the good things found in other ecosystems’ approach to TUI frameworks. It offers a multi-layer API: from low-level widget primitives (like Ratatui), to a managed TUI layer with event handling, up to a declarative Toolkit DSL that handles the event loop and rendering thread for you—things that Ratatui doesn’t really cover. This brings the power of Ratatui, Textual or Rich to the Java ecosystem, with the Java touch!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Not only that, TamboUI is also &lt;a href=&quot;https://www.graalvm.org/latest/reference-manual/native-image/&quot;&gt;GraalVM native&lt;/a&gt; compatible! This means that you can compile your Java TUI applications as native binaries, making Java a first class citizen in terminal applications development, with low memory footprints and fast startup!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you want to give it a try, the easiest is to run our demos using &lt;a href=&quot;https://www.jbang.dev/&quot;&gt;JBang&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;shell&quot;&gt;jbang demos@tamboui&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_try_it_out&quot;&gt;Try it out&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, the APIs are still unstable and subject to change. TamboUI is developed with the mindset of being framework-agnostic and having as few external dependencies as possible. You can choose between several backends like &lt;a href=&quot;https://jline.org/&quot;&gt;JLine&lt;/a&gt;, &lt;a href=&quot;https://aeshell.github.io/&quot;&gt;Aesh&lt;/a&gt; or the built-in Panama backend. By choosing the latter, you’ll get the best performance while not depending on any external library.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Whether you want to build:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a standalone CLI tool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an internal developer tool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a DevOps utility&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;add a TUI frontend to existing Java tool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an AI agent&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;or something entirely new&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Give TamboUI a try and let us know what worked and what could be improved!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Check out the documentation at &lt;a href=&quot;https://tamboui.dev/docs/main/&quot; class=&quot;bare&quot;&gt;https://tamboui.dev/docs/main/&lt;/a&gt;, join us on &lt;a href=&quot;https://tamboui.zulipchat.com&quot;&gt;Zulip&lt;/a&gt;, or browse the source on &lt;a href=&quot;https://github.com/tamboui/tamboui&quot;&gt;GitHub&lt;/a&gt;. We&amp;#8217;d love your feedback and contributions!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We would like to thank the following people for their ideas, suggestions and contributions to the creation of first public release of TamboUI (in alphabetical order):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Charles Moulliard&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Claus Ibsen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Graeme Rocher&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume LaForge&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;James Cobb&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ståle Pedersen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tako Schotanus&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and of course to the Ratatui and Textual creators for their inspiration and work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;openblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Max Rydahl Andersen &amp;amp; Cédric Champeau&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Mesurer la rotation différentielle solaire avec JSol&amp;#8217;Ex</title>
      <link>https://melix.github.io/blog//2026/02/06-mesure-rotation-differentielle.html</link>
      <pubDate>Thu, 5 Feb 2026 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2026/02/06-mesure-rotation-differentielle.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_une_boule_de_plasma_en_rotation&quot;&gt;Une boule de plasma en rotation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;un des aspects fascinants du Soleil est qu&amp;#8217;il ne tourne pas comme un corps solide.
Contrairement à la Terre, qui effectue une rotation en 24 heures quelle que soit la latitude, la vitesse de rotation du Soleil varie avec la latitude : l&amp;#8217;équateur tourne plus vite que les pôles.
Ce phénomène, appelé &lt;strong&gt;rotation différentielle&lt;/strong&gt;, est étudié depuis le 19ème siècle et reste un sujet de recherche important en physique solaire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les régions équatoriales du Soleil effectuent une rotation en environ 25 jours, tandis que près des pôles, cela prend environ 35 jours.
Cette rotation différentielle joue un rôle clé dans le mécanisme de dynamo solaire qui génère le champ magnétique du Soleil et pilote le cycle solaire de 11 ans.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/differential-rotation-concept-fr.svg&quot; alt=&quot;Concept de rotation différentielle&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans cet article, je vais expliquer comment j&amp;#8217;ai ajouté une fonctionnalité dans JSol&amp;#8217;Ex 4.5.0 qui permet aux astronomes amateurs de mesurer cette rotation différentielle directement à partir d&amp;#8217;un scan obtenu avec un spectrohéliographe.
Une erreur fréquente est de penser que cette mesure n&amp;#8217;est pas possible parce que la dispersion spectrale d&amp;#8217;un spectrographe comme le Sol&amp;#8217;Ex est typiquement d&amp;#8217;environ 0.1 à 0.2 Å, c&amp;#8217;est-à-dire plus grand que l&amp;#8217;échelle de ce que nous essayons de mesurer (2 km/s, soit environ 0.04 Å).
En pratique, nous devrons obtenir une précision sub-pixellaire et cet article explique comment y arriver.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_leffet_doppler&quot;&gt;L&amp;#8217;effet Doppler&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le principe derrière la mesure est simple : l&apos;&lt;strong&gt;effet Doppler&lt;/strong&gt;.
Quand une source lumineuse se déplace vers nous, la longueur d&amp;#8217;onde est décalée vers le bleu du spectre (blueshift).
Quand elle s&amp;#8217;éloigne, la longueur d&amp;#8217;onde se décale vers le rouge (redshift).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Puisque le Soleil tourne, un limbe se déplace toujours vers nous (le limbe Est) tandis que l&amp;#8217;autre s&amp;#8217;éloigne (le limbe Ouest).
En mesurant le décalage de longueur d&amp;#8217;onde d&amp;#8217;une raie spectrale aux deux limbes, nous pouvons calculer la vitesse de rotation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/doppler-effect-sun-fr.svg&quot; alt=&quot;Effet Doppler pour mesurer la rotation solaire&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On pourrait se demander ce qu&amp;#8217;il en est du mouvement propre de la Terre : nous orbitons autour du Soleil à environ 30 km/s, ce qui est bien plus grand que la vitesse de rotation solaire d&amp;#8217;environ 2 km/s que nous essayons de mesurer.
Ce mouvement orbital produit effectivement un décalage Doppler de tout le spectre solaire.
Cependant, cet effet s&amp;#8217;applique de manière égale à tous les points que nous pouvons mesurer : en d&amp;#8217;autres termes, puisque tout le spectre est décalé de manière uniforme, tout s&amp;#8217;annule.
Il en va de même pour toute vitesse radiale du Soleil par rapport à la Terre (qui varie légèrement tout au long de l&amp;#8217;année car l&amp;#8217;orbite de la Terre est elliptique).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La formule fondamentale reliant le décalage Doppler à la vitesse est :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\frac{\Delta\lambda}{\lambda_0} = \frac{v}{c}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Où :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\Delta\lambda\) est le décalage en longueur d&amp;#8217;onde (ce qu&amp;#8217;on cherche à mesurer)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(\lambda_0\) est la longueur d&amp;#8217;onde au repos de la raie spectrale (typiquement la longueur d&amp;#8217;onde H-alpha)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(v\) est la vitesse le long de la ligne de visée&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(c\) est la vitesse de la lumière (299 792 km/s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_méthodologie_de_mesure&quot;&gt;La méthodologie de mesure&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_travaux_antérieurs&quot;&gt;Travaux antérieurs&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je ne suis pas la première personne à essayer de faire cette mesure en spectrohéliographie amateur.
En 2017, Peter Zetner &lt;a href=&quot;https://www.cloudynights.com/forums/topic/574571-solar-differential-rotation-measured-with-a-spectroheliograph/&quot;&gt;a expliqué sur CloudyNights&lt;/a&gt; comment mesurer la vitesse différentielle en utilisant un spectrohéliographe.
Il a expliqué cette méthodologie en profondeur dans le livre &lt;a href=&quot;https://astronomiesolaire.com/&quot;&gt;Astronomie solaire - Observer, photographier et étudier le Soleil&lt;/a&gt;.
Sa méthodologie repose sur des mesures utilisant la raie Na D2. mais peut aussi être appliquée sur d&amp;#8217;autres raies brillantes incluant la raie Fe I couramment utilisée à 5250.2 Å, et implique de comparer les intensités des pixels, en les moyennant à différentes latitudes.
Les résultats sont meilleurs en effectuant plusieurs scans et en moyennant les données.
Bien que cela fonctionne, je voulais essayer une méthodologie différente :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Utiliser un seul scan : les images Doppler que JSol&amp;#8217;Ex ou INTI peuvent produire sont en général très cohérentes et montrent que toutes les données dont nous avons besoin sont déjà présentes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Éviter les intensités de pixels : celles-ci sont très sensibles à l&amp;#8217;assombrissement centre-bord, aux conditions d&amp;#8217;observation (par exemple les nuages, même fins) ou au vignetage (assombrissement des images le long de la fente)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rendre possible l&amp;#8217;utilisation de scans H-alpha, non pas parce qu&amp;#8217;ils donneraient une valeur précise de la vitesse du plasma de la photosphère, mais parce que c&amp;#8217;est la raie la plus largement imagée dans les observations solaires amateurs&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les résultats, bien sûr, dépendront de la raie observée.
La méthodologie que je décris ci-dessous est capable de retourner des résultats raisonnables sur plusieurs raies (H-alpha, Na D2. Fe I) mais échouera complètement sur certaines autres (par exemple Ca II K, typiquement parce que la raie est trop large).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Plongeons-nous dans la méthodologie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
L&amp;#8217;implémentation décrite ici a été développée de manière itérative basée sur des observations réelles. Je ne suis pas physicien solaire, juste un ingénieur essayant d&amp;#8217;extraire des données significatives des captures de spectrohéliographe. L&amp;#8217;algorithme fonctionne raisonnablement bien en pratique mais devrait être validé par rapport à des mesures professionnelles pour toute application scientifique. C&amp;#8217;est pourquoi cette fonctionnalité est annoncée comme expérimentale.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_comparaison_des_limbes_est_ouest&quot;&gt;Comparaison des limbes Est-Ouest&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La clé pour comprendre la méthodologie est qu&amp;#8217;elle repose sur l&amp;#8217;analyse et l&amp;#8217;ajustement de profils de raies spectrales.
Elle nécessite d&amp;#8217;extraire les profils de raies spectrales à différents endroits du disque solaire, de préférence près des limbes où les vitesses sont les plus élevées (plus on s&amp;#8217;approche du méridien solaire, plus les vitesses sont faibles et donc difficiles à détecter).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La mesure de rotation différentielle extrait les vitesses de rotation solaire en comparant les décalages Doppler entre les points des limbes Est et Ouest à la même latitude héliographique.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/spectral-profiles-fr.svg&quot; alt=&quot;Profils spectraux décalés&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour chaque latitude (par exemple, 20° Nord), l&amp;#8217;algorithme :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Sélectionne un point sur le limbe Est&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sélectionne le point correspondant sur le limbe Ouest à la même latitude&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mesure la position de la raie spectrale à chaque point&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Calcule la différence : Ouest - Est&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette approche différentielle a un avantage crucial : elle annule les erreurs systématiques.
Tout décalage instrumental, erreur de calibration en longueur d&amp;#8217;onde, ou décalage de référence affecte les deux mesures de manière égale et disparaît quand nous prenons la différence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cependant, une seule mesure Est-Ouest à chaque latitude n&amp;#8217;est pas assez fiable.
Les conditions de seeing, l&amp;#8217;activité solaire locale, ou les erreurs d&amp;#8217;ajustement peuvent corrompre les mesures individuelles.
Pour améliorer la précision, JSol&amp;#8217;Ex échantillonne &lt;strong&gt;plusieurs longitudes&lt;/strong&gt; à travers la région du limbe (typiquement 14 points de 62° à 88° de longitude) et agrège ces mesures.
Cette redondance permet de rejeter les valeurs aberrantes et fournit une estimation d&amp;#8217;erreur basée sur la cohérence des mesures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La vitesse mesurée est alors :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[v_{measured} = \frac{\Delta\lambda}{\lambda_0} \times \frac{c}{2}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le facteur 2 apparaît parce que nous mesurons la différence entre les limbes s&amp;#8217;approchant et s&amp;#8217;éloignant.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_de_la_vitesse_mesurée_à_la_vitesse_équatoriale&quot;&gt;De la vitesse mesurée à la vitesse équatoriale&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La vitesse que nous mesurons dépend de la géométrie : quelle fraction de la vitesse de rotation est projetée le long de notre ligne de visée.
À l&amp;#8217;équateur et au limbe, nous voyons la vitesse de rotation complète.
À des latitudes plus élevées ou plus près du centre du disque, nous n&amp;#8217;en voyons qu&amp;#8217;une fraction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le facteur de correction géométrique est :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[v_{equatorial} = \frac{v_{measured}}{\cos(\phi) \times \sin(\theta)}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Où :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\phi\) est la latitude héliographique&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(\theta\) est la longitude héliographique (0° au centre du disque, ±90° aux limbes)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_trouver_le_centre_de_la_raie_spectrale&quot;&gt;Trouver le centre de la raie spectrale&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La partie la plus difficile de la mesure est de déterminer précisément le centre de la raie d&amp;#8217;absorption.
Un décalage de seulement 0.01 Å correspond à une vitesse d&amp;#8217;environ 0.5 km/s, ce qui est significatif par rapport à la vitesse équatoriale typique d&amp;#8217;environ 2 km/s.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex utilise l&apos;&lt;strong&gt;ajustement de profil de Voigt&lt;/strong&gt; pour mesurer le centre de la raie.
Le profil de Voigt est la convolution d&amp;#8217;un profil gaussien et d&amp;#8217;un profil lorentzien, qui modélise précisément la forme des raies d&amp;#8217;absorption solaires.
La composante gaussienne représente l&amp;#8217;élargissement Doppler thermique, tandis que la composante lorentzienne représente l&amp;#8217;élargissement naturel et de pression.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour chaque point de mesure, l&amp;#8217;algorithme :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Extrait un profil spectral du fichier SER à la position correspondante&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ajuste un profil de Voigt à la raie d&amp;#8217;absorption&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enregistre la position du centre de raie ajustée&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le paramètre configurable &quot;demi-largeur d&amp;#8217;ajustement de Voigt&quot; (par défaut : 2 Å) contrôle quelle proportion des ailes de la raie sont incluses dans l&amp;#8217;ajustement.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_systèmes_de_coordonnées&quot;&gt;Systèmes de coordonnées&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;un des aspects les plus délicats de cette implémentation est de transformer correctement les coordonnées que nous manipulons.
L&amp;#8217;algorithme commence avec les coordonnées héliographiques (où nous voulons mesurer) et les transforme en coordonnées des trames SER originales (où les données spectrales se trouvent).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;1. Coordonnées héliographiques (point de départ)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous commençons par spécifier des points en coordonnées héliographiques :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latitude&lt;/strong&gt; : -90° (pôle sud) à +90° (pôle nord)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Longitude&lt;/strong&gt; : 0° au centre du disque, ±90° aux limbes&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cela nécessite deux paramètres solaires calculés à partir de la date d&amp;#8217;observation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;B0&lt;/strong&gt; : La latitude héliographique du centre du disque (varie tout au long de l&amp;#8217;année)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;P&lt;/strong&gt; : L&amp;#8217;angle de position de l&amp;#8217;axe de rotation (l&amp;#8217;inclinaison du Soleil vu depuis la Terre)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;2. Coordonnées image&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les coordonnées héliographiques sont converties en positions de pixels dans l&amp;#8217;image reconstruite.
Cela implique d&amp;#8217;inverser les corrections appliquées pendant la reconstruction :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Correction de l&amp;#8217;angle P&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retournement/rotation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Distorsion géométrique&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Angle d&amp;#8217;inclinaison&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Recadrage&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;3. Coordonnées du fichier SER (destination)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finalement, les coordonnées image sont mappées vers le fichier vidéo SER brut :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Numéro de trame&lt;/strong&gt; : Position dans la séquence de scan (dérivée de la coordonnée x)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Colonne&lt;/strong&gt; : Position le long de la fente (dérivée de la coordonnée y)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ligne&lt;/strong&gt; : Direction spectrale (longueur d&amp;#8217;onde)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce mapping inverse nous permet d&amp;#8217;extraire le profil spectral exact à n&amp;#8217;importe quelle position héliographique.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_pipeline_de_traitement_des_données&quot;&gt;Le pipeline de traitement des données&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les mesures brutes sont bruitées.
Pour produire une courbe de rotation propre, JSol&amp;#8217;Ex utilise un pipeline de traitement en deux étapes :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_étape_1_agrégation_en_longitude&quot;&gt;Étape 1 : Agrégation en longitude&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comme décrit précédemment, à chaque latitude, plusieurs longitudes sont échantillonnées (typiquement 14 points à travers la région du limbe).
Ces mesures sont combinées en utilisant l&amp;#8217;une des trois méthodes (la médiane par défaut mais vous pouvez choisir) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Médiane&lt;/strong&gt; : Robuste aux valeurs aberrantes, utilise la valeur centrale&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Moyenne&lt;/strong&gt; : Simple moyenne arithmétique&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Moyenne pondérée&lt;/strong&gt; : Les points plus proches du limbe (où le signal Doppler est plus fort) ont un poids plus élevé&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;estimation d&amp;#8217;erreur de cette étape représente la cohérence des mesures à travers les longitudes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_étape_2_lissage_en_latitude&quot;&gt;Étape 2 : Lissage en latitude&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Même après l&amp;#8217;agrégation en longitude, les mesures latitude par latitude restent bruitées.
Les bins de latitude individuels peuvent encore être affectés par des caractéristiques localisées (taches solaires, facules) ou simplement par la dispersion des mesures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Puisque nous nous attendons à ce que la rotation solaire varie &lt;strong&gt;de manière lisse&lt;/strong&gt; avec la latitude (suivant les termes \(\sin^2\phi\) et \(\sin^4\phi\) de la loi de rotation différentielle), nous pouvons exploiter cette contrainte physique pour réduire davantage le bruit.
JSol&amp;#8217;Ex applique un filtre de lissage qui combine les points de latitude voisins dans une fenêtre configurable (par défaut : 5°).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;De manière importante, les erreurs de l&amp;#8217;étape 1 sont &lt;strong&gt;propagées&lt;/strong&gt; plutôt que recalculées à partir de la dispersion dans la fenêtre de lissage.
Cela garantit que les barres d&amp;#8217;erreur représentent l&amp;#8217;incertitude de mesure, pas les variations physiques de latitude.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour l&amp;#8217;agrégation médiane :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\sigma_{smoothed} = \frac{median(\sigma_i)}{\sqrt{n}}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour la moyenne :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\sigma_{smoothed} = \frac{\sqrt{\sum \sigma_i^2}}{n}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_résultat_et_la_comparaison_avec_la_théorie&quot;&gt;Le résultat et la comparaison avec la théorie&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La forme standard de la loi de rotation différentielle (aussi connue comme la formule de Faye, même si la formule originale n&amp;#8217;incluait pas le 3ème terme) est :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\omega(\phi) = A + B \sin^2(\phi) + C \sin^4(\phi)\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Où :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\phi\) est la latitude héliographique&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(A\) est le taux de rotation équatorial&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(B\) et \(C\) contrôlent la diminution de la vitesse avec la latitude&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex compare les résultats mesurés avec les coefficients largement utilisés de &lt;strong&gt;Snodgrass &amp;amp; Ulrich (1990)&lt;/strong&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(A = 14.713\) deg/jour (taux de rotation équatorial)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(B = -2.396\) deg/jour&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(C = -1.787\) deg/jour&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cela donne une période de rotation équatoriale d&amp;#8217;environ 24.5 jours et une période polaire d&amp;#8217;environ 34 jours.
Convertie en vitesse linéaire à la surface solaire (rayon ≈ 696 000 km), la vitesse de rotation équatoriale est d&amp;#8217;environ 2.0 km/s.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex ajuste également ses propres coefficients A, B, C à partir de vos mesures, permettant une comparaison directe avec les valeurs de référence.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_résultats&quot;&gt;Résultats&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ci-dessous des exemples de profils de rotation différentielle mesurés avec JSol&amp;#8217;Ex en utilisant deux raies spectrales différentes.
Ces mesures ont été prises à des dates différentes avec des conditions de seeing différentes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_fe_i_5883_å&quot;&gt;Fe I 5883 Å&lt;/h3&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/velocity-FeI.png&quot; alt=&quot;velocity FeI&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_h_alpha&quot;&gt;H-alpha&lt;/h3&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/velocity-Ha.png&quot; alt=&quot;velocity Ha&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_observations&quot;&gt;Observations&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les profils mesurés montrent la forme générale attendue : des vitesses plus élevées à l&amp;#8217;équateur, diminuant vers les pôles.
Les courbes ajustées suivent raisonnablement bien le profil théorique de Snodgrass.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cependant, j&amp;#8217;observe des différences entre les raies spectrales que je ne peux pas entièrement expliquer.
Les mesures Fe I montrent des vitesses absolues différentes de H-alpha, et les coefficients ajustés diffèrent entre les scans.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Plusieurs facteurs pourraient contribuer à ces différences :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hauteur de formation&lt;/strong&gt; : Différentes raies spectrales se forment à différentes hauteurs dans l&amp;#8217;atmosphère solaire, et les taux de rotation peuvent varier avec l&amp;#8217;altitude (comme suggéré par des recherches récentes de la &lt;a href=&quot;https://www.nature.com/articles/s41550-024-02299-4&quot;&gt;mission CHASE&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Conditions de seeing&lt;/strong&gt; : Les scans ont été pris à des dates différentes avec des conditions atmosphériques différentes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Différences de profil de raie&lt;/strong&gt; : H-alpha et Fe I ont des largeurs et profondeurs de raie différentes, ce qui peut affecter la précision de l&amp;#8217;ajustement de Voigt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Effets systématiques&lt;/strong&gt; : Il peut y avoir des facteurs instrumentaux ou algorithmiques que je n&amp;#8217;ai pas identifiés&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je présente ces résultats tels qu&amp;#8217;ils sont, sans essayer de tirer des conclusions sur quelle mesure est &quot;correcte&quot; ou ce qui cause les différences observées.
Plus de mesures sur différentes dates, raies spectrales et instruments seraient nécessaires pour comprendre ces variations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_mesurer_en_pratique&quot;&gt;Mesurer en pratique&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La qualité des résultats dépend fortement du seeing atmosphérique.
Un mauvais seeing floute les raies spectrales et rend la détermination précise du centre difficile.
Les meilleurs résultats sont obtenus avec d&amp;#8217;excellentes conditions de seeing et un instrument bien focalisé.
Enfin et surtout, une haute résolution spectrale est préférée, ce qui est normalement le cas avec le Sol&amp;#8217;Ex (HR) ou le SHG 700.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Vous pouvez aussi vous demander quelle raie spectrale vous devriez observer.
J&amp;#8217;ai testé l&amp;#8217;algorithme avec Fe I, Na D2 et H-alpha, donnant les résultats ci-dessous.
En pratique, les raies d&amp;#8217;absorption fortes devraient en théorie produire les meilleurs résultats, car :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;La profondeur de raie devrait être suffisante pour un ajustement précis&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Les ailes devraient être bien définies pour l&amp;#8217;ajustement de Voigt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Le rapport signal sur bruit devrait être élevé&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les raies très larges comme Ca II K sont trop larges pour un ajustement de Voigt précis et produiront des résultats peu fiables.
Les raies trop étroites peuvent aussi représenter un défi pour l&amp;#8217;ajustement de Voigt mais peuvent fonctionner aussi.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_limpact_de_la_détection_de_la_raie_spectrale&quot;&gt;L&amp;#8217;impact de la détection de la raie spectrale&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un facteur subtil mais important affectant la précision absolue des mesures est la &lt;strong&gt;correction polynomiale&lt;/strong&gt; utilisée pendant la reconstruction d&amp;#8217;image.
Comprendre ceci est essentiel pour interpréter correctement vos résultats.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pendant le traitement du spectrohéliographe, JSol&amp;#8217;Ex calcule un polynôme qui fait correspondre chaque position de colonne le long de la fente vers la position de ligne attendue du centre de la raie spectrale.
Ce polynôme est calculé à partir de la &lt;strong&gt;moyenne des trames SER&lt;/strong&gt; dans le scan (une heuristique est utilisée pour inclure les trames contenant des données solaires réelles, pas le fond de ciel).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une telle détection est cruciale car la raie spectrale n&amp;#8217;est pas droite à travers la fente en raison de phénomènes optiques : elle constitue ce que nous appelons souvent le &quot;smile&quot;.
Par conséquent, le centre de raie peut être à la ligne 300 à la colonne 500. mais à la ligne 350 à la colonne 1000.
Le polynôme capture cette courbure.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En mesurant les positions de raie &lt;strong&gt;relativement au polynôme&lt;/strong&gt;, nous éliminons efficacement la distorsion optique de nos mesures.
Sans cette référence, nous mesurerions la somme de la courbure optique plus le décalage Doppler, rendant impossible l&amp;#8217;extraction des minuscules signaux de vitesse que nous recherchons.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une question clé est : pourquoi ne pouvons-nous pas simplement mesurer la position absolue de la raie spectrale dans chaque trame et calculer les vitesses directement ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La réponse réside dans la précision requise.
Une vitesse de 2 km/s correspond à un décalage de longueur d&amp;#8217;onde de seulement ~0.04 Å à H-alpha.
Avec une dispersion spectrale typique de 0.1-0.2 Å/pixel, c&amp;#8217;est un décalage de seulement &lt;strong&gt;0.2 à 0.4 pixels&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La courbure optique à travers la fente, d&amp;#8217;autre part, peut facilement s&amp;#8217;étendre sur 10-30 pixels ou plus.
Toute tentative de mesurer les positions absolues de raie serait complètement dominée par cette courbure, rendant la détection Doppler impossible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le polynôme sert de &lt;strong&gt;référence de base&lt;/strong&gt;.
En mesurant comment la position de raie dans chaque trame individuelle &lt;strong&gt;dévie du polynôme&lt;/strong&gt;, nous isolons la composante Doppler de la composante optique.
C&amp;#8217;est l&amp;#8217;idée clé qui rend les mesures de précision sub-pixellaire possibles, avec l&amp;#8217;ajustement de Voigt.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_un_mot_sur_les_images_doppler&quot;&gt;Un mot sur les images Doppler&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci, d&amp;#8217;ailleurs, est aussi une raison pour laquelle les images Doppler sont différentes quand on scanne en AD vs DEC.
Parce que c&amp;#8217;est une question souvent posée, et qu&amp;#8217;il m&amp;#8217;a fallu &lt;strong&gt;des mois&lt;/strong&gt; pour comprendre la raison, je pense qu&amp;#8217;il vaut la peine de passer un peu de temps à expliquer le phénomène.
Je dois cette explication à Jean-François Pittet et Christian Buil, d&amp;#8217;une discussion il y a quelques semaines sur la mailing list Sol&amp;#8217;Ex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_scan_en_ad_vs_scan_en_dec_une_différence_critique_pour_les_images_doppler&quot;&gt;Scan en AD vs scan en DEC : une différence critique pour les images Doppler&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les spectrohéliographes peuvent scanner le Soleil dans deux directions :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scan en AD&lt;/strong&gt; (Ascension Droite) : La fente est orientée Nord-Sud, et le scan procède Est-Ouest&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scan en DEC&lt;/strong&gt; (Déclinaison) : La fente est orientée Est-Ouest, et le scan procède Nord-Sud&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce choix a des &lt;strong&gt;implications profondes&lt;/strong&gt; pour la visibilité Doppler, comme expliqué par Jean-François Pittet sur la mailing list Sol&amp;#8217;Ex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_scan_en_ad_doppler_visible_dans_les_images&quot;&gt;Scan en AD : Doppler visible dans les images&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En mode scan AD, chaque trame capture une tranche verticale du Soleil du pôle Nord au pôle Sud.
Au cours du scan :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Les premières trames capturent le &lt;strong&gt;limbe Est&lt;/strong&gt; (s&amp;#8217;approchant, décalé vers le bleu)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Les trames du milieu capturent le &lt;strong&gt;centre du disque&lt;/strong&gt; (pas de vitesse radiale)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Les dernières trames capturent le &lt;strong&gt;limbe Ouest&lt;/strong&gt; (s&amp;#8217;éloignant, décalé vers le rouge)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Quand JSol&amp;#8217;Ex calcule le polynôme à partir de la moyenne de toutes les trames, les contributions Est et Ouest &lt;strong&gt;s&amp;#8217;équilibrent&lt;/strong&gt;.
Le blueshift du limbe Est est annulé par le redshift du limbe Ouest.
Le polynôme résultant représente la référence &quot;neutre&quot; : approximativement la position de raie au centre du disque sans décalage Doppler.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En conséquence, quand nous reconstruisons l&amp;#8217;image au décalage de pixel 0. les décalages Doppler deviennent &lt;strong&gt;visibles comme différences de contraste&lt;/strong&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Le limbe Est apparaît plus sombre (raie décalée dans la bande passante)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Le limbe Ouest apparaît plus clair (raie décalée hors de la bande passante)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est pourquoi les images Doppler des scans AD montrent l&amp;#8217;asymétrie caractéristique Est-Ouest.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_scan_en_dec_doppler_absorbé_par_le_polynôme&quot;&gt;Scan en DEC : Doppler &quot;absorbé&quot; par le polynôme&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En mode scan DEC, chaque trame capture une tranche horizontale du Soleil d&amp;#8217;Est en Ouest.
Voici la différence critique : &lt;strong&gt;tous les pixels dans une seule trame voient approximativement le même décalage Doppler&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Par exemple, si la trame actuelle capture la moitié Est du disque :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Tous les points dans cette trame s&amp;#8217;approchent de nous&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tous les points ont un blueshift similaire&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Quand JSol&amp;#8217;Ex calcule le polynôme à partir de la moyenne de toutes les trames, il ne capture pas seulement la courbure optique : il capture aussi le &lt;strong&gt;décalage Doppler moyen&lt;/strong&gt; à travers le scan.
Mais voici le problème : le décalage Doppler varie systématiquement à travers le scan (les trames Est sont décalées vers le bleu, les trames Ouest sont décalées vers le rouge).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le polynôme &quot;absorbe&quot; effectivement une moyenne pondérée de ces décalages Doppler.
Quand nous mesurons ensuite les positions de raie relativement à ce polynôme, une grande partie du signal Doppler a déjà été soustraite.
Les images Doppler résultantes ne &lt;strong&gt;montreront plus la rotation du soleil&lt;/strong&gt; (ce qui peut aussi être un avantage, pour d&amp;#8217;autres types d&amp;#8217;observations).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est pourquoi les spectrohéliographes expérimentés préfèrent souvent le scan AD pour le travail Doppler : le signal Doppler est plus visible et plus facile à détecter.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_la_complication_de_langle_p&quot;&gt;La complication de l&amp;#8217;angle P&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il y a une subtilité supplémentaire : l&amp;#8217;axe de rotation du Soleil n&amp;#8217;est pas perpendiculaire à l&amp;#8217;écliptique.
L&apos;&lt;strong&gt;angle P&lt;/strong&gt; (angle de position de l&amp;#8217;axe de rotation) varie tout au long de l&amp;#8217;année d&amp;#8217;environ -26° à +26°.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Deux fois par an (vers début juin et début décembre) l&amp;#8217;angle P est proche de zéro.
À ces moments :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Le scan AD est vraiment parallèle à l&amp;#8217;équateur solaire&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Le motif Doppler Est-Ouest s&amp;#8217;aligne parfaitement avec la direction de scan&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;À d&amp;#8217;autres moments, quand P est non nul :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;L&amp;#8217;axe de rotation est incliné par rapport à la direction de scan&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Le motif Doppler est tourné par rapport aux axes de l&amp;#8217;image&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Une partie du signal Doppler &quot;fuit&quot; dans la moyenne polynomiale même en mode AD&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est une des raisons pour lesquelles les mesures de rotation différentielle peuvent montrer des résultats légèrement différents à différentes périodes de l&amp;#8217;année, bien que nous prenions en compte les angles P et B0.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_implications_pour_les_mesures_de_rotation_différentielle&quot;&gt;Implications pour les mesures de rotation différentielle&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci explique pourquoi le &lt;strong&gt;scan AD est essentiel&lt;/strong&gt; pour les mesures de vitesse différentielle :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En mode AD, les points des limbes Est et Ouest à la même latitude correspondent à la &lt;strong&gt;même colonne&lt;/strong&gt; sur la fente (même position de fente, trames différentes).
La valeur du polynôme à cette colonne est calculée à partir de la moyenne de toutes les trames (limbe Est, centre du disque, et limbe Ouest) donc les décalages Doppler s&amp;#8217;annulent dans la moyenne.
Quand nous calculons &lt;code&gt;(Ouest - polynôme) - (Est - polynôme)&lt;/code&gt;, les termes du polynôme sont identiques et s&amp;#8217;annulent, nous laissant avec la vraie différence Doppler &lt;code&gt;Ouest - Est&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En mode DEC, les points des limbes Est et Ouest à la même latitude correspondent aux &lt;strong&gt;extrémités opposées de la fente&lt;/strong&gt; (colonnes différentes, même trame).
Le polynôme à la colonne Est est calculé à partir de trames qui &lt;strong&gt;voient toutes le limbe Est&lt;/strong&gt; à cette position, donc le polynôme absorbe le blueshift.
De même, le polynôme à la colonne Ouest absorbe le redshift.
Quand nous calculons la différence, ces décalages Doppler absorbés ne s&amp;#8217;annulent pas : ils &lt;strong&gt;se soustraient&lt;/strong&gt; de notre mesure, réduisant significativement le signal mesuré.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est pourquoi, en pratique, les scans DEC ne produisent pas d&amp;#8217;images Doppler utilisables ou de mesures de vitesse différentielle fiables.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_conseils_de_configuration&quot;&gt;Conseils de configuration&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Longitude du limbe&lt;/strong&gt; (par défaut 75°) : Les mesures plus proches du limbe donnent des signaux Doppler plus forts mais risquent des effets d&amp;#8217;assombrissement centre-bord&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pas de latitude&lt;/strong&gt; (par défaut 2°) : Des valeurs plus petites donnent une résolution plus fine mais des temps de traitement plus longs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fenêtre de lissage&lt;/strong&gt; : Devrait être au moins 2× le pas de latitude pour un lissage efficace&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mesurer la rotation différentielle avec du matériel amateur aurait semblé impossible il y a quelques années seulement.
Des pionniers comme Peter Zetner ou Christian Buil nous ont montré la voie.
Ce que j&amp;#8217;essaie de faire, comme toujours avec JSol&amp;#8217;Ex, c&amp;#8217;est de rendre ceci accessible à encore plus de personnes au prix de la &quot;magie&quot;, c&amp;#8217;est-à-dire que certaines personnes partageront très probablement des résultats sans comprendre la science derrière.
Je ne suis pas trop inquiet par cela, parce que je suis moi-même passé par là : apprécier la reconstruction d&amp;#8217;images SHG, puis comprendre comment ça fonctionne, puis me poser des questions comme &quot;pourquoi est-il même possible de mesurer des vitesses Doppler si petites ?&quot; : c&amp;#8217;est une construction intellectuelle qui prend du temps.
Nous, membres de la communauté Sol&amp;#8217;Ex, pouvons faire mieux, je pense, pour apporter cela aux masses, en partageant nos idées et en écrivant des logiciels comme celui-ci.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette fonctionnalité rejoint la liste croissante des capacités scientifiques dans JSol&amp;#8217;Ex : détection des bombes d&amp;#8217;Ellerman, identification des régions actives, et maintenant mesure de la rotation différentielle.
Chacune de celles-ci met des analyses de niveau professionnel à la portée des astronomes amateurs, mais, comme toujours, soyez prudent avec ce que je dis : je ne suis pas un scientifique, juste un ingénieur.
Je n&amp;#8217;ai aucun doute que j&amp;#8217;ai fait des approximations, ou pris des libertés que je n&amp;#8217;aurais probablement pas dû prendre.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_bibliographie&quot;&gt;Bibliographie&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_articles_scientifiques&quot;&gt;Articles scientifiques&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/1951MNRAS.111..413N/abstract&quot;&gt;Newton, H.W. &amp;amp; Nunn, M.L. (1951) - The Sun&amp;#8217;s rotation derived from sunspots 1934-1944. MNRAS 111, 413&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1007/BF02276562&quot;&gt;Howard, R. &amp;amp; Harvey, J. (1970) - Spectroscopic determinations of solar rotation. Sol Phys 12. 23-51&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1007/BF00154804&quot;&gt;Snodgrass, H.B. (1984) - Separation of large-scale photospheric Doppler patterns. Sol Phys 94, 13-31&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1086/168467&quot;&gt;Snodgrass, H.B. &amp;amp; Ulrich, R.K. (1990) - Rotation of Doppler features in the solar photosphere. ApJ 351, 309&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1023/A:1005226402796&quot;&gt;Beck, J.G. (2000) - A comparison of differential rotation measurements. Sol Phys 191, 47-70&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/2000A%26A&amp;#8230;&amp;#8203;357..763W/abstract&quot;&gt;Wöhl, H. &amp;amp; Schmidt, W. (2000) - Solar equatorial plasma rotation: a comparison of different spectroscopic measurements. A&amp;amp;A 357, 763-766&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/2406.18271&quot;&gt;Takeda, Y. &amp;amp; Ueno, S. (2024) - Measurement of Solar Differential Rotation by Absolutely Calibrated Iodine-Cell Spectroscopy&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.aanda.org/articles/aa/full_html/2025/10/aa56102-25/aa56102-25.html&quot;&gt;Corbard, T. et al. (2025) - Rotational radial shear in the low solar photosphere. A&amp;amp;A 702. A93&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nature.com/articles/s41550-024-02299-4&quot;&gt;Li, Z. et al. (2024) - Height-dependent differential rotation of the solar atmosphere detected by CHASE. Nature Astronomy&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_ressources_amateurs&quot;&gt;Ressources amateurs&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cloudynights.com/forums/topic/574571-solar-differential-rotation-measured-with-a-spectroheliograph/&quot;&gt;Zetner, P. (2017) - Solar differential rotation measured with a spectroheliograph (CloudyNights)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://solar-astronomy-book.com/&quot;&gt;Zetner, P. et al. - Solar Astronomy: Observing, imaging and studying the Sun&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.astrosurf.com/solex/&quot;&gt;Sol&amp;#8217;Ex - Projet de spectrohéliographe de Christian Buil&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html&quot;&gt;Documentation JSol&amp;#8217;Ex&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Measuring Solar Differential Rotation with JSol&amp;#8217;Ex</title>
      <link>https://melix.github.io/blog//2026/02/05-measuring-solar-rotation.html</link>
      <pubDate>Thu, 5 Feb 2026 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2026/02/05-measuring-solar-rotation.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_rotating_ball_of_plasma&quot;&gt;A Rotating Ball of Plasma&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One fascinating aspect of the Sun is that it doesn&amp;#8217;t rotate like a solid body.
Unlike the Earth, which completes one rotation in 24 hours regardless of latitude, the Sun&amp;#8217;s rotation rate varies with latitude: the equator rotates faster than the poles.
This phenomenon, called &lt;strong&gt;differential rotation&lt;/strong&gt;, has been studied since the 19th century and remains an important research topic in solar physics.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The equatorial regions of the Sun complete a rotation in approximately 25 days, while near the poles, it takes about 35 days.
This differential rotation is thought to play a key role in the solar dynamo mechanism that generates the Sun&amp;#8217;s magnetic field and drives the 11-year solar cycle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/differential-rotation-concept.svg&quot; alt=&quot;Differential rotation concept&quot; width=&quot;600&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, I will explain how I implemented a feature in JSol&amp;#8217;Ex 4.5.0 that allows amateur astronomers to measure this differential rotation directly from their spectroheliograph data.
A common mistake is to think that this measurement is not possible because the spectral dispersion of a SHG like the Sol&amp;#8217;Ex is typically around 0.1 to 0.2Å, which larger than the scale of what we&amp;#8217;re trying to measure (2 km/s, which is about 0.04Å).
In fact, what we are trying to measure requires sub-pixel precision and we can achieve that.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_doppler_effect&quot;&gt;The Doppler Effect&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The principle behind the measurement is simple: the &lt;strong&gt;Doppler effect&lt;/strong&gt;.
When a light source moves towards us, the wavelength is shifted towards the blue end of the spectrum (blueshift).
When it moves away, the wavelength shifts towards the red (redshift).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since the Sun rotates, one limb is always moving towards us (let&amp;#8217;s say the East limb) while the other is moving away (the West limb).
By measuring the wavelength shift of a spectral line at both limbs, we can calculate the rotation velocity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/doppler-effect-sun.svg&quot; alt=&quot;Doppler effect for measuring solar rotation&quot; width=&quot;700&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One might wonder about the Earth&amp;#8217;s own motion: we orbit the Sun at approximately 30 km/s, which is much larger than the ~2 km/s solar rotation velocity we&amp;#8217;re trying to measure.
This orbital motion does produce a Doppler shift of the entire solar spectrum.
However, this affects equally all points we can measure: this is a global shift which affects all measurements equally and cancels out.
The same is true for any radial velocity of the Sun relative to the Earth (which varies slightly throughout the year as Earth&amp;#8217;s orbit is elliptical).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The fundamental formula relating Doppler shift to velocity is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\frac{\Delta\lambda}{\lambda_0} = \frac{v}{c}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\Delta\lambda\) is the wavelength shift&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(\lambda_0\) is the rest wavelength of the spectral line (typically the H-alpha wavelength)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(v\) is the velocity along the line of sight&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(c\) is the speed of light (299,792 km/s)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_measurement_methodology&quot;&gt;The Measurement Methodology&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_previous_work&quot;&gt;Previous Work&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am not the first person to try to make this measurement in amateur spectroheliography.
In 2017, Peter Zetner &lt;a href=&quot;https://www.cloudynights.com/forums/topic/574571-solar-differential-rotation-measured-with-a-spectroheliograph/&quot;&gt;explained on CloudyNights&lt;/a&gt; how to measure differential velocity using a spectroheliograph.
He explained this methodology in depth in the &lt;a href=&quot;https://solar-astronomy-book.com/&quot;&gt;Solar Astronomy - Observing, imaging and studying the Sun&lt;/a&gt; book.
His methodology relies on measurements using the Na D2 line, but can also be applied on other bright lines including the commonly used Fe I line at 5250.2 Å, and involves comparing the pixel intensities, by averaging them at different latitudes.
The best results are obtained by performing several scans and averaging data.
While this works, I wanted to try a different methodology:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Use a single scan: the Doppler images that JSol&amp;#8217;Ex or INTI can produce are in general very consistent and show that all the data we need is already present&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid pixel intensities: these are very sensitive to limb darkening, observing conditions (e.g clouds, even if thin) or vignetting (darkening of the images along the slit)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make it possible to use H-alpha scans, not because they would give an accurate value of the velocity of the photosphere plasma, but because that&amp;#8217;s the most widely imaged line in amateur solar observations&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The results, of course, will depend on the observed line.
The methodology that I describe below is capable of returning reasonable results on several lines (H-alpha, Na D2, Fe I) but will completely fail on some others (e.g Ca II K, typically because the line is too wide).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s dive into the methodology.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
The implementation described here was developed iteratively based on real observations. I&amp;#8217;m not a solar physicist, just an engineer trying to extract meaningful data from spectroheliograph captures. The algorithm works reasonably well in practice but should be validated against professional measurements for any scientific application. Therefore why it is advertised as experimental.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_east_west_limb_comparison&quot;&gt;East-West Limb Comparison&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The key to understanding the methodology is that it relies on spectral line profile analysis and fitting.
It requires extracting the spectral line profiles at different locations of the solar disk, preferably near the limbs where the velocities are highest.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The differential rotation measurement extracts solar rotation velocities by comparing Doppler shifts between East and West limb points at the same heliographic latitude.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/spectral-profiles.svg&quot; alt=&quot;Doppler Shifted Profiles&quot; width=&quot;500&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For each latitude (say, 20° North), the algorithm:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Selects a point on the East limb&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Selects the corresponding point on the West limb at the same latitude&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Measures the spectral line position at each point&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Computes the difference: West - East&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This differential approach has a crucial advantage: it cancels out systematic errors.
Any instrumental offset, wavelength calibration error, or baseline shift affects both measurements equally and disappears when we take the difference.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, a single East-West measurement at each latitude is not reliable enough.
Seeing conditions, local solar activity, or fitting errors can corrupt individual measurements.
To improve accuracy, JSol&amp;#8217;Ex samples &lt;strong&gt;multiple longitudes&lt;/strong&gt; across the limb region (typically 14 points from 62° to 88° longitude) and aggregates these measurements.
This redundancy allows outliers to be rejected and provides an error estimate based on measurement consistency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The measured velocity is then:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[v_{measured} = \frac{\Delta\lambda}{\lambda_0} \times \frac{c}{2}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The factor of 2 appears because we&amp;#8217;re measuring the difference between approaching and receding limbs.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_from_measured_velocity_to_equatorial_velocity&quot;&gt;From Measured Velocity to Equatorial Velocity&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The velocity we measure depends on the geometry: how much of the rotation velocity is projected along our line of sight.
At the equator and at the limb, we see the full rotation velocity.
At higher latitudes or closer to disk center, we see only a fraction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The geometric correction factor is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[v_{equatorial} = \frac{v_{measured}}{\cos(\phi) \times \sin(\theta)}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\phi\) is the heliographic latitude&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(\theta\) is the heliographic longitude (0° at disk center, ±90° at the limbs)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_finding_the_spectral_line_center&quot;&gt;Finding the Spectral Line Center&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The most challenging part of the measurement is accurately determining the center of the absorption line.
A shift of just 0.01 Å corresponds to a velocity of about 0.5 km/s, which is significant compared to the typical equatorial velocity of ~2 km/s.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex uses &lt;strong&gt;Voigt profile fitting&lt;/strong&gt; to measure the line center.
The Voigt profile is the convolution of a Gaussian and a Lorentzian profile, which accurately models the shape of solar absorption lines.
The Gaussian component represents thermal Doppler broadening, while the Lorentzian component represents natural and pressure broadening.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For each measurement point, the algorithm:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Extracts a spectral profile from the SER file at the corresponding position&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fits a Voigt profile to the absorption line&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Records the fitted line center position&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The configurable &quot;Voigt fit half-width&quot; parameter (default: 2 Å) controls how much of the line wings are included in the fit.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_coordinate_systems&quot;&gt;Coordinate Systems&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the trickier aspects of this implementation is correctly mapping between the different coordinate systems involved.
The algorithm starts with heliographic coordinates (where we want to measure) and maps them back to the original SER frames (where the spectral data lives).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;1. Heliographic Coordinates (starting point)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We begin by specifying points in heliographic coordinates:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latitude&lt;/strong&gt;: -90° (south pole) to +90° (north pole)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Longitude&lt;/strong&gt;: 0° at disk center, ±90° at the limbs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This requires two solar parameters computed from the observation date:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;B0&lt;/strong&gt;: The heliographic latitude of the disk center (varies throughout the year)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;P&lt;/strong&gt;: The position angle of the rotation axis (the &quot;tilt&quot; of the Sun as seen from Earth)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;2. Image Coordinates&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The heliographic coordinates are converted to pixel positions in the reconstructed image.
This involves reversing the corrections applied during reconstruction:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;P-angle correction&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Flip/rotation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Geometric distortion&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tilt angle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cropping&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;3. SER File Coordinates (destination)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finally, the image coordinates are mapped to the raw SER video file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frame number&lt;/strong&gt;: Position in the scan sequence (derived from x-coordinate)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Column&lt;/strong&gt;: Position along the slit (derived from y-coordinate)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Row&lt;/strong&gt;: Spectral direction (wavelength)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This reverse mapping allows us to extract the exact spectral profile at any heliographic location.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_data_processing_pipeline&quot;&gt;The Data Processing Pipeline&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The raw measurements are noisy.
To produce a clean rotation curve, JSol&amp;#8217;Ex uses a two-stage processing pipeline:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_stage_1_longitude_aggregation&quot;&gt;Stage 1: Longitude Aggregation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As described earlier, at each latitude, multiple longitudes are sampled (typically 14 points across the limb region).
These measurements are combined using one of three methods (the default is median but you can choose):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Median&lt;/strong&gt;: Robust to outliers, uses the middle value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Average&lt;/strong&gt;: Simple arithmetic mean&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weighted Average&lt;/strong&gt;: Points closer to the limb (where Doppler signal is stronger) get higher weight&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The error estimate from this stage represents the consistency of measurements across longitudes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_stage_2_latitude_smoothing&quot;&gt;Stage 2: Latitude Smoothing&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even after longitude aggregation, the latitude-by-latitude measurements remain noisy.
Individual latitude bins can still be affected by localized features (sunspots, faculae) or simply measurement scatter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since we expect solar rotation to vary &lt;strong&gt;smoothly&lt;/strong&gt; with latitude (following the \(\sin^2\phi\) and \(\sin^4\phi\) terms of the differential rotation law), we can exploit this physical constraint to reduce noise further.
JSol&amp;#8217;Ex applies a smoothing filter that combines nearby latitude points within a configurable window (default: 5°).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Importantly, the errors from Stage 1 are &lt;strong&gt;propagated&lt;/strong&gt; rather than recomputed from the spread in the smoothing window.
This ensures the error bars represent measurement uncertainty, not physical latitude variations.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the median aggregation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\sigma_{smoothed} = \frac{median(\sigma_i)}{\sqrt{n}}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the average:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\sigma_{smoothed} = \frac{\sqrt{\sum \sigma_i^2}}{n}\]
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_outcome_and_comparison_with_theory&quot;&gt;The Outcome and Comparison with Theory&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The standard form of the differential rotation law (also known as the Faye formula, even if the original formula didn&amp;#8217;t include the 3rd term) is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;stemblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
\[\omega(\phi) = A + B \sin^2(\phi) + C \sin^4(\phi)\]
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Where:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(\phi\) is the heliographic latitude&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(A\) is the equatorial rotation rate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(B\) and \(C\) control the decrease in velocity with latitude&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex compares measured results with the widely-used coefficients from &lt;strong&gt;Snodgrass &amp;amp; Ulrich (1990)&lt;/strong&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;\(A = 14.713\) deg/day (equatorial rotation rate)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(B = -2.396\) deg/day&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;\(C = -1.787\) deg/day&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This gives an equatorial rotation period of about 24.5 days and a polar period of about 34 days.
Converting to linear velocity at the solar surface (radius ≈ 696,000 km), the equatorial rotation velocity is approximately 2.0 km/s.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex also fits its own A, B, C coefficients from your measurements, allowing direct comparison with the reference values.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_results&quot;&gt;Results&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Below are example differential rotation profiles measured with JSol&amp;#8217;Ex using two different spectral lines.
These measurements were taken on different dates with different seeing conditions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_fe_i_5883_å&quot;&gt;Fe I 5883 Å&lt;/h3&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/velocity-FeI.png&quot; alt=&quot;velocity FeI&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_h_alpha&quot;&gt;H-alpha&lt;/h3&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-diff-velocity/velocity-Ha.png&quot; alt=&quot;velocity Ha&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_observations&quot;&gt;Observations&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The measured profiles show the expected general shape: higher velocities at the equator, decreasing toward the poles.
The fitted curves follow the theoretical Snodgrass profile reasonably well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, I observe differences between spectral lines that I cannot fully explain.
The Fe I measurements show different absolute velocities than H-alpha, and the fitted coefficients differ between scans.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Several factors could contribute to these differences:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Formation height&lt;/strong&gt;: Different spectral lines form at different heights in the solar atmosphere, and rotation rates may vary with height (as suggested by recent research from the &lt;a href=&quot;https://www.nature.com/articles/s41550-024-02299-4&quot;&gt;CHASE mission&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Seeing conditions&lt;/strong&gt;: The scans were taken on different dates with different atmospheric conditions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Line profile differences&lt;/strong&gt;: H-alpha and Fe I have different line widths and depths, which may affect the Voigt fitting precision&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Systematic effects&lt;/strong&gt;: There may be instrumental or algorithmic factors I haven&amp;#8217;t identified&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I present these results as they are, without attempting to draw conclusions about which measurement is &quot;correct&quot; or what causes the observed differences.
More measurements across different dates, spectral lines, and instruments would be needed to understand these variations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_measuring_in_practice&quot;&gt;Measuring in Practice&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The quality of results depends heavily on atmospheric seeing.
Poor seeing blurs the spectral lines and makes accurate center determination difficult.
Best results are obtained with excellent seeing conditions and a well-focused instrument.
Last but not least, a high spectral resolution is preferred, which is normally the case with Sol&amp;#8217;Ex (HR) or the SHG 700.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You may also wonder which spectral line you should observe.
I tested the algorithm with Fe I, Na D2 and H-alpha, giving the results below.
In practice, strong absorption lines should in theory produce the best results, because:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The line depth should be sufficient for accurate fitting&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The wings should be well-defined for Voigt fitting&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The signal-to-noise ratio should be high&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Very broad lines like Ca II K are too wide for accurate Voigt fitting and will produce unreliable results.
Too narrow lines may also represent a challenge for Voigt fitting but may work too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_impact_of_the_spectral_line_detection&quot;&gt;The Impact of the Spectral Line Detection&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One subtle but important factor affecting the absolute accuracy of the measurements is the &lt;strong&gt;polynomial correction&lt;/strong&gt; used during image reconstruction.
Understanding this is essential for interpreting your results correctly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;During spectroheliograph processing, JSol&amp;#8217;Ex computes a polynomial that maps each column position along the slit to the expected row position of the spectral line center.
This polynomial is computed from the &lt;strong&gt;average of SER frames&lt;/strong&gt; in the scan (a heuristic is used to include frames containing actual solar data, not sky background).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Such a detection is crucial because the spectral line is not straight across the slit due to optical phenomenons: it consistutes what we often call the &quot;smile&quot;.
Therefore, the line center might be at row 300 at column 500, but at row 350 at column 1000.
The polynomial captures this curvature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By measuring line positions &lt;strong&gt;relative to the polynomial&lt;/strong&gt;, we effectively remove the optical distortion from our measurements.
Without this reference, we would be measuring the sum of optical curvature plus Doppler shift, making it impossible to extract the tiny velocity signals we&amp;#8217;re after.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A key question is: why can&amp;#8217;t we just measure the absolute position of the spectral line in each frame and compute velocities directly?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The answer lies in the precision required.
A velocity of 2 km/s corresponds to a wavelength shift of only ~0.04 Å at H-alpha.
With a typical spectral dispersion of 0.1-0.2 Å/pixel, this is a shift of only &lt;strong&gt;0.2 to 0.4 pixels&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The optical curvature across the slit, on the other hand, can easily span 10-30 pixels or more.
Any attempt to measure absolute line positions would be completely dominated by this curvature, making Doppler detection impossible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The polynomial serves as our &lt;strong&gt;reference baseline&lt;/strong&gt;.
By measuring how the line position in each individual frame &lt;strong&gt;deviates from the polynomial&lt;/strong&gt;, we isolate the Doppler component from the optical component.
This is the key insight that makes sub-pixel precision measurements possible, alongside the Voigt fitting.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_a_word_about_doppler_images&quot;&gt;A Word About Doppler Images&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This, by the way, is also a reason why the Doppler images look different when scanning in RA vs DEC.
Because this is a question that is often asked, and that it took &lt;strong&gt;months&lt;/strong&gt; for me to understand the reason, I think it&amp;#8217;s worth spending a bit of time explaining the phenomenon.
I owe this explanation to Jean-François Pittet and Christian Buil, from a discussion weeks ago on the Sol&amp;#8217;Ex mailing list.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_ra_scanning_vs_dec_scanning_a_critical_difference_for_doppler_images&quot;&gt;RA Scanning vs DEC Scanning: A Critical Difference for Doppler Images&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Spectroheliographs can scan the Sun in two directions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;RA scanning&lt;/strong&gt; (Right Ascension): The slit is oriented North-South, and the scan proceeds East-West&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DEC scanning&lt;/strong&gt; (Declination): The slit is oriented East-West, and the scan proceeds North-South&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This choice has &lt;strong&gt;profound implications&lt;/strong&gt; for Doppler visibility, as explained by Jean-François Pittet on the Sol&amp;#8217;Ex mailing list.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_ra_scanning_doppler_visible_in_images&quot;&gt;RA Scanning: Doppler Visible in Images&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In RA scanning mode, each frame captures a vertical slice of the Sun from North pole to South pole.
Over the course of the scan:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Early frames capture the &lt;strong&gt;East limb&lt;/strong&gt; (approaching, blueshifted)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Middle frames capture the &lt;strong&gt;disk center&lt;/strong&gt; (no radial velocity)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Late frames capture the &lt;strong&gt;West limb&lt;/strong&gt; (receding, redshifted)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When JSol&amp;#8217;Ex computes the polynomial from the average of all frames, the East and West contributions &lt;strong&gt;balance out&lt;/strong&gt;.
The blueshift from the East limb is canceled by the redshift from the West limb.
The resulting polynomial represents the &quot;neutral&quot; baseline: approximately the line position at disk center with no Doppler shift.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a result, when we reconstruct the image at pixel shift 0, the Doppler shifts become &lt;strong&gt;visible as contrast differences&lt;/strong&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;East limb appears darker (line shifted into the passband)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;West limb appears brighter (line shifted out of the passband)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is why Doppler images from RA scans show the characteristic East-West asymmetry.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect4&quot;&gt;
&lt;h5 id=&quot;_dec_scanning_doppler_absorbed_by_the_polynomial&quot;&gt;DEC Scanning: Doppler &quot;Absorbed&quot; by the Polynomial&lt;/h5&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In DEC scanning mode, each frame captures a horizontal slice of the Sun from East to West.
Here&amp;#8217;s the critical difference: &lt;strong&gt;all pixels within a single frame see approximately the same Doppler shift&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, if the current frame is capturing the Eastern half of the disk:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All points in that frame are approaching us&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;All points have similar blueshift&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When JSol&amp;#8217;Ex computes the polynomial from the average of all frames, it doesn&amp;#8217;t just capture the optical curvature: it also captures the &lt;strong&gt;average Doppler shift&lt;/strong&gt; across the scan.
But here&amp;#8217;s the problem: the Doppler shift varies systematically across the scan (East frames are blueshifted, West frames are redshifted).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The polynomial effectively &quot;absorbs&quot; a weighted average of these Doppler shifts.
When we then measure line positions relative to this polynomial, much of the Doppler signal has already been subtracted out.
The resulting Doppler images will &lt;strong&gt;no longer show the rotation of the sun&lt;/strong&gt; (which can also be a benefit, for other kind of observations).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is why experienced spectroheliographers often prefer RA scanning for Doppler work: the Doppler signal is more visible and easier to detect.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_the_p_angle_complication&quot;&gt;The P-Angle Complication&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There&amp;#8217;s an additional subtlety: the Sun&amp;#8217;s rotation axis is not perpendicular to the ecliptic.
The &lt;strong&gt;P-angle&lt;/strong&gt; (position angle of the rotation axis) varies throughout the year from about -26° to +26°.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Only twice per year (around early June and early December) is the P-angle close to zero.
At these times:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;RA scanning is truly parallel to the solar equator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The East-West Doppler pattern aligns perfectly with the scan direction&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At other times, when P is non-zero:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The rotation axis is tilted relative to the scan direction&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Doppler pattern is rotated relative to the image axes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some Doppler signal &quot;leaks&quot; into the polynomial average even in RA mode&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is one reason why differential rotation measurements can show slightly different results at different times of year, despite us taking the P and B0 angles into account.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_implications_for_differential_rotation_measurements&quot;&gt;Implications for Differential Rotation Measurements&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This explains why &lt;strong&gt;RA scanning is essential&lt;/strong&gt; for differential velocity measurements:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In RA mode, East and West limb points at the same latitude correspond to the &lt;strong&gt;same column&lt;/strong&gt; on the slit (same slit position, different frames).
The polynomial value at that column is computed from the average of all frames (East limb, disk center, and West limb) so the Doppler shifts cancel out in the average.
When we compute &lt;code&gt;(West - polynomial) - (East - polynomial)&lt;/code&gt;, the polynomial terms are identical and cancel, leaving us with the true Doppler difference &lt;code&gt;West - East&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In DEC mode, East and West limb points at the same latitude correspond to &lt;strong&gt;opposite ends of the slit&lt;/strong&gt; (different columns, same frame).
The polynomial at the East column is computed from frames that &lt;strong&gt;all see the East limb&lt;/strong&gt; at that position, so the polynomial absorbs the blueshift.
Similarly, the polynomial at the West column absorbs the redshift.
When we compute the difference, these absorbed Doppler shifts don&amp;#8217;t cancel: they &lt;strong&gt;subtract from&lt;/strong&gt; our measurement, significantly reducing the measured signal.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is why, in practice, DEC scans do not produce usable Doppler images or reliable differential velocity measurements.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_configuration_tips&quot;&gt;Configuration Tips&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Limb longitude&lt;/strong&gt; (default 75°): Measurements closer to the limb give stronger Doppler signals but risk limb darkening effects&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Latitude step&lt;/strong&gt; (default 2°): Smaller values give finer resolution but longer processing times&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Smoothing window&lt;/strong&gt;: Should be at least 2× the latitude step for effective smoothing&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Measuring differential rotation with amateur equipment would have seemed impossible just a few years ago.
Pioneers like Peter Zetner or Christian Buil showed us the path.
What I&amp;#8217;m trying to do, as always with JSol&amp;#8217;Ex, is to make this accessible to even more people at the cost of &quot;magic&quot;, which is that some people will very likely share results without understanding the science behind it.
I&amp;#8217;m not too concerned by this, as I, myself, have been going this way: enjoying SHG image reconstruction, then figuring out how it works, then asking myself questions like &quot;why is it even possible that we measure Doppler velocities so small?&quot;: this is an intellectual construct that takes time and we can do better, I think, at brining this to the masses, sharing our insights.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This feature joins the growing list of scientific capabilities in JSol&amp;#8217;Ex: Ellerman bomb detection, active region identification, and now differential rotation measurement.
Each of these brings professional-level analysis within reach of amateur astronomers, but, as always, be cautious with what I&amp;#8217;m saying: I&amp;#8217;m not a scientist, just an engineer.
I have no doubts that I made approximations, or took liberties that I should probably not have taken.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, I do think that this brings value to the ecosystem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_bibliography&quot;&gt;Bibliography&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_scientific_papers&quot;&gt;Scientific Papers&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/1951MNRAS.111..413N/abstract&quot;&gt;Newton, H.W. &amp;amp; Nunn, M.L. (1951) - The Sun&amp;#8217;s rotation derived from sunspots 1934-1944. MNRAS 111, 413&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1007/BF02276562&quot;&gt;Howard, R. &amp;amp; Harvey, J. (1970) - Spectroscopic determinations of solar rotation. Sol Phys 12, 23-51&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1007/BF00154804&quot;&gt;Snodgrass, H.B. (1984) - Separation of large-scale photospheric Doppler patterns. Sol Phys 94, 13-31&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1086/168467&quot;&gt;Snodgrass, H.B. &amp;amp; Ulrich, R.K. (1990) - Rotation of Doppler features in the solar photosphere. ApJ 351, 309&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://doi.org/10.1023/A:1005226402796&quot;&gt;Beck, J.G. (2000) - A comparison of differential rotation measurements. Sol Phys 191, 47-70&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/2000A%26A&amp;#8230;&amp;#8203;357..763W/abstract&quot;&gt;Wöhl, H. &amp;amp; Schmidt, W. (2000) - Solar equatorial plasma rotation: a comparison of different spectroscopic measurements. A&amp;amp;A 357, 763-766&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/2406.18271&quot;&gt;Takeda, Y. &amp;amp; Ueno, S. (2024) - Measurement of Solar Differential Rotation by Absolutely Calibrated Iodine-Cell Spectroscopy&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.aanda.org/articles/aa/full_html/2025/10/aa56102-25/aa56102-25.html&quot;&gt;Corbard, T. et al. (2025) - Rotational radial shear in the low solar photosphere. A&amp;amp;A 702, A93&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nature.com/articles/s41550-024-02299-4&quot;&gt;Li, Z. et al. (2024) - Height-dependent differential rotation of the solar atmosphere detected by CHASE. Nature Astronomy&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_amateur_resources&quot;&gt;Amateur Resources&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cloudynights.com/forums/topic/574571-solar-differential-rotation-measured-with-a-spectroheliograph/&quot;&gt;Zetner, P. (2017) - Solar differential rotation measured with a spectroheliograph (CloudyNights)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://solar-astronomy-book.com/&quot;&gt;Zetner, P. et al. - Solar Astronomy: Observing, imaging and studying the Sun&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.astrosurf.com/solex/&quot;&gt;Sol&amp;#8217;Ex - Christian Buil&amp;#8217;s spectroheliograph project&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://melix.github.io/astro4j/latest/en/jsolex.html&quot;&gt;JSol&amp;#8217;Ex Documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JSol&amp;#8217;Ex 4.0.0 est sorti !</title>
      <link>https://melix.github.io/blog//2025/09-11-jsolex-4.0.0.html</link>
      <pubDate>Thu, 11 Sep 2025 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2025/09-11-jsolex-4.0.0.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le 18 février 2023, je montais à l&amp;#8217;Observatoire du Pic du Midi de Bigorre pour y passer une &quot;Nuit au Sommet&quot;, une expérience mêlant observation nocturne et visite des installations scientifiques. J&amp;#8217;y ai découvert avec fascination le coronographe Bernard-Lyot, l&amp;#8217;expérience &lt;a href=&quot;https://climso.fr/&quot;&gt;CLIMSO&lt;/a&gt; gérée par les Observateurs Associés de l&amp;#8217;Observatoire Midi-Pyrénées.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Des étoiles plein les yeux (et une en particulier, notre soleil), ma vie d&amp;#8217;astronome amateur centrée sur le ciel profond allait basculer vers l&amp;#8217;observation de notre Soleil. De retour à la maison, j&amp;#8217;ai commencé à me renseigner sur le matériel solaire, et découvrait avec stupéfaction qu&amp;#8217;il fallait investir, beaucoup, pour pouvoir observer notre astre en toute sécurité : filtres pleine ouverture, étalons, &amp;#8230;&amp;#8203; tout avait un coût démesuré pour un débutant comme moi. De quoi décourager, jusqu&amp;#8217;à ce que je tombe par hasard &lt;a href=&quot;http://www.astrosurf.com/solex/&quot;&gt;sur le projet Sol&amp;#8217;Ex&lt;/a&gt;, initié par la légende Christian Buil.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce projet, très didactique, permet de se construire un spectrohéliographe, par impression 3D. Un tel instrument présente de nombreux avantages : coût modeste, résolution élevée et la possibilité d&amp;#8217;observer dans de nombreuses longueurs d&amp;#8217;ondes tout en mettant à disposition des données exploitables scientifiquement !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;inconvénient, si c&amp;#8217;en est vraiment un, de cet instrument est qu&amp;#8217;il ne produit pas une image du soleil observable directement à l&amp;#8217;oculaire. Il est nécessaire d&amp;#8217;utiliser un logiciel de reconstruction qui, à partir d&amp;#8217;une vidéo enregistrant un &quot;scan&quot; du soleil, permet de générer une (voir plus) images du soleil. Ce processus de reconstruction, bien mystérieux pour moi à l&amp;#8217;époque, était réalisé par un &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;logiciel écrit par Valérie Desnoux, nommé INTI&lt;/a&gt;. Etant développeur (Java), je me suis alors lancé un challenge à l&amp;#8217;époque : puisque je ne comprenais pas comment ça fonctionnait, j&amp;#8217;allais essayer de créer moi-même un logiciel pour faire cette reconstruction. De cet appétit est né &lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_jsolex_4_0_et_la_collaboration_scientifique&quot;&gt;JSol&amp;#8217;Ex 4.0 et la collaboration scientifique&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous voici 2 ans et demi plus tard, JSol&amp;#8217;Ex arrive en version 4. Entre temps, le nombre d&amp;#8217;utilisateurs a explosé et mon logiciel est exploité non seulement par les utilisateurs du Sol&amp;#8217;Ex de Christian Buil, mais aussi pour des spectrohéliographes commerciaux comme le &lt;a href=&quot;https://mlastro.com/mlastro-shg&quot;&gt;MLAstro SHG 700&lt;/a&gt; (que j&amp;#8217;utilise désormais). JSol&amp;#8217;Ex a apporté de nombreuses innovations, comme la possibilité d&amp;#8217;exécuter des scripts pour générer des animations, faire du stacking, créer des images personnalisées, ou encore la détection automatique d&amp;#8217;éruptions, des régions actives (avec annotation), la détection de bombes d&amp;#8217;Ellerman, la correction des bords dentelés et j&amp;#8217;en passe.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Récemment, JSol&amp;#8217;Ex a été utilisé pour réaliser un &lt;a href=&quot;https://iopscience.iop.org/article/10.3847/2515-5172/adef50&quot;&gt;Atlas de Spectrohéliogrammes&lt;/a&gt;, et mentionné dans &lt;a href=&quot;https://arxiv.org/abs/2508.10853&quot;&gt;un article précisément sur la détection des bombes d&amp;#8217;Ellerman&lt;/a&gt;. Bref, JSol&amp;#8217;Ex était devenu suffisamment mature pour faire de la &quot;vraie science&quot;, chose qui m&amp;#8217;a toujours un peu effrayé pour être honnête.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, j&amp;#8217;ai toujours refusé d&amp;#8217;intégrer une fonctionnalité dans JSol&amp;#8217;Ex, qui m&amp;#8217;a pourtant été demandée de nombreuses fois : la possibilité de l&amp;#8217;utiliser pour soumettre des images dans la &lt;a href=&quot;https://bass2000.obspm.fr/&quot;&gt;base de données BASS2000&lt;/a&gt; de l&amp;#8217;&lt;a href=&quot;https://www.linkedin.com/school/lira-observatoire-de-paris/&quot;&gt;Observatoire de Paris-Meudon&lt;/a&gt;. Plusieurs raisons à cela : d&amp;#8217;une, je ne faisais pas confiance à mon propre logiciel pour sa qualité &quot;scientifique&quot;. Si je le savais capable de produire de &quot;belles images&quot;, il est tout à fait différent de s&amp;#8217;en servir pour une exploitation scientifique. D&amp;#8217;autre part, il n&amp;#8217;était pas question pour moi d&amp;#8217;intégrer une fonctionnalité qui avait été développée par Valérie Desnoux (autrice de INTI) et l&amp;#8217;équipe de Meudon sans son accord, par respect pour son travail.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cependant, vous aurez compris que les temps ont changé et que la pression des utilisateurs ainsi que mes discussions avec Florence Cornu, du projet SOLAP, aux Rencontres du Ciel et de l&amp;#8217;Espace fin 2024, puis aux &lt;a href=&quot;https://www.mars60.fr/jason2025/&quot;&gt;JASON&lt;/a&gt; en Juin dernier ont eu raison de mes doutes. Avec son accord et celui de Valérie, je suis donc heureux de vous annoncer que JSol&amp;#8217;Ex 4 est officiellement supporté pour soumettre vos images dans la base de données BASS 2000 !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_un_assistant_pas_à_pas&quot;&gt;Un assistant pas à pas&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ne souhaitant pas faire les choses à moitié, j&amp;#8217;ai particulièrement peaufiné le logiciel pour simplifier cette procédure. J&amp;#8217;ai souhaité faire les choses avec sérieux, puisqu&amp;#8217;il s&amp;#8217;agit d&amp;#8217;une base de données professionnelle, exploitée par des scientifiques. Ainsi, une chose importante pour moi était de guider l&amp;#8217;utilisateur dans ce processus et de lui faire comprendre l&amp;#8217;importance de la qualité des données, tout en simplifiant le processus de soumission.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-4.0/bass2000.jpg&quot; alt=&quot;bass2000&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Figure 1. Assistant de soumission BASS2000&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi par exemple, BASS2000 n&amp;#8217;a que très peu de tolérance sur les problèmes d&amp;#8217;orientation de l&amp;#8217;image : il faut que le Nord solaire soit à moins de 1 degré d&amp;#8217;erreur, sinon l&amp;#8217;image sera refusée. L&amp;#8217;assistant intègre donc un outil pour aider à vérifier l&amp;#8217;orientation et corriger les erreurs minimes dues par exemple à une mise en station imparfaite.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;assistant guidera aussi l&amp;#8217;utilisateur dans son processus de soumission, en lui demandant de bien vérifier toutes les métadonnées associées à l&amp;#8217;observation, et ira jusqu&amp;#8217;à envoyer l&amp;#8217;image sur le serveur FTP de BASS2000 pour validation par les équipes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis particulièrement reconnaissant à Florence CORNU pour son aide afin que les images JSol&amp;#8217;Ex soient acceptées dans la base et je remercie mes beta-testeurs qui ont patiemment testé mes versions de développement pendant l&amp;#8217;été.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je ne vous cache pas qu&amp;#8217;il s&amp;#8217;agit là d&amp;#8217;une forme de reconnaissance de mon travail, des centaines d&amp;#8217;heures passées soirs et week-ends à développer ce logiciel qui rappelons-le est &lt;a href=&quot;https://github.com/melix/astro4j&quot;&gt;entièrement Open Source et gratuit&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, je ne peux pas m&amp;#8217;arrêter sans vous annoncer une deuxième bonne nouvelle : non seulement vous pourrez utiliser JSol&amp;#8217;Ex pour soumettre vos images acquises avec un Sol&amp;#8217;Ex, mais aussi avec le MLAstro SHG 700, qui devient officiellement supporté dans la base BASS2000 !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_changements_dans_linterface&quot;&gt;Changements dans l&amp;#8217;interface&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour cette version j&amp;#8217;ai aussi souhaité moderniser un peu l&amp;#8217;interface graphique et la simplifier : avec le nombre de fonctionnalités croissantes arrive ce moment fatidique que tout développeur redoute : que l&amp;#8217;interface ne devienne trop complexe pour les nouveaux utilisateurs et ne parle qu&amp;#8217;aux anciens. J&amp;#8217;ai essayé d&amp;#8217;éviter cet écueil au cours du temps en refusant certaines fonctionnalités trop &quot;de niche&quot;, mais sans pouvoir pour autant réussir à avoir une interface totalement claire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-4.0/interface-overview.jpg&quot; alt=&quot;interface overview&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Figure 2. Aperçu des changements d&amp;#8217;interface&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette nouvelle version essaie donc de regrouper les paramètres par sections plus claires, tout en ajoutant des infobulles pour guider les utilisateurs, anciens comme nouveaux, dans cet esprit qui est que le logiciel se doit d&amp;#8217;être le plus didactique possible : j&amp;#8217;essaie, autant que faire se peut, de vous transmettre en tant qu&amp;#8217;utilisateurs ce que moi-même j&amp;#8217;apprends en développant ce logiciel. Un exemple frappant de cette philosophie, c&amp;#8217;est cette fonctionnalité que j&amp;#8217;avais ajoutée qui permet de montrer en cliquant sur le disque solaire, à quelle image il correspond dans le fichier source (une vidéo contenant des spectres).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_détection_dellipse_assistée_par_lutilisateur&quot;&gt;Détection d&amp;#8217;ellipse assistée par l&amp;#8217;utilisateur&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je vous parlais un peu plus haut de l&amp;#8217;Atlas des Spectrohéliogrammes. Cet atlas, réalisé par Pál Váradi Nagy, nécessite un travail énorme d&amp;#8217;analyse des données et est réalisé à l&amp;#8217;aide de scripts JSol&amp;#8217;Ex. Cependant, pour certaines longueurs d&amp;#8217;ondes ou pour parfois des images un peu compliquées à traiter, le logiciel peut échouer à détecter correctement les contours du disque solaire. Ceci peut arriver notamment lorsque les images sont peu contrastées ou lorsqu&amp;#8217;il y a des réflexions internes qui biaisent la détection.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Afin de résoudre ces cas complexes qui, encore une fois, nuisent à l&amp;#8217;analyse scientifiques, j&amp;#8217;ai ajouté la possibilité d&amp;#8217;aider le logiciel à détecter les contours, et ainsi à obtenir un image solaire bien ronde:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-4.0/ellipse-detection-assistant.jpg&quot; alt=&quot;ellipse detection assistant&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Figure 3. Détection d&amp;#8217;ellipse assistée par l&amp;#8217;utilisateur&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_lia_à_la_rescousse&quot;&gt;L&amp;#8217;IA à la rescousse&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis développeur et en tant que tel, sur ce media, il me semblait pertinent d&amp;#8217;ajouter une section sur la façon dont cette version a été développée.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette version est la première version qui a été développée avec l&amp;#8217;aide de l&amp;#8217;IA, en particulier Claude Code. En effet, les dernières innovations en matière d&amp;#8217;IA agentique sont pour le coup la véritable révolution à venir : autant avant, avoir une IA qui n&amp;#8217;était pas capable de comprendre le contexte, faire des refactorings ou prévoir un plan de développement ne les rendait pas particulièrement utiles, autant les IA à base d&amp;#8217;agents, qui sont capables d&amp;#8217;analyser votre code, appeler des outils de manière autonome et avoir de vraies interactions avec vous sont un &quot;game changer&quot; de mon point de vue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans cette version, j&amp;#8217;ai donc utilisé Claude Code (plan Pro) pour m&amp;#8217;aider à faire les refactorings dont j&amp;#8217;avais besoin et m&amp;#8217;assister dans une tâche où je ne suis pas particulièrement à l&amp;#8217;aise : le design d&amp;#8217;interfaces graphiques.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;De manière générale, ça fonctionne plutôt bien. Très bien même. La capacité de l&amp;#8217;outil à définir un plan d&amp;#8217;implémentation et comprendre les besoins est assez fascinante. Le code généré, en revanche, nécessite toujours beaucoup de review. On pourrait dire que j&amp;#8217;ai l&amp;#8217;impression d&amp;#8217;avoir un (très bon) stagiaire avec moi, en permanence. En tant que développeur senior, je suis assez rapide à identifier là où l&amp;#8217;IA complique les choses inutilement, ou utilise des design pattern dépréciés, ou ne respecte pas les conventions de code. Je serai, par exemple, terrifié si le code original produit était parti en production sans review. Mais, en lui donnant les bonnes directions, en lui expliquant ses erreurs, on arrive rapidement à ce que l&amp;#8217;on souhaite avec la qualité que l&amp;#8217;on souhaite.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Quelques exemples de choses qui ne fonctionnent pour le coup vraiment pas bien:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Claude vous demande de créer un fichier CLAUDE.md qui comprend des instructions sur comment compiler votre projet, comment il est organisé, etc. Bref, du contexte qui est systématiquement ajouté à chaque session. Pourtant, à l&amp;#8217;utilisation, Claude ignore allègrement ces instructions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;En Java, les fichiers .properties sont encodés en ISO-8859-1, même dans une base où tous les sources sont en UTF-8. C&amp;#8217;est une bizarrerie historique, mais Claude ne la comprend absolument pas. A chaque fois qu&amp;#8217;il modifie mes fichiers properties (qui servent à l&amp;#8217;internationalisation de l&amp;#8217;interface), il casse systématiquement l&amp;#8217;encodage. Pour l&amp;#8217;éviter, le dois systématiquement, avant de lui faire faire une opération dont je sais qu&amp;#8217;elle implique ces fichiers, lui dire &quot;respecte les guidelines du fichier CLAUDE&quot; où je lui ai donné une technique pour éviter les problèmes (convertir le fichier en UTF-8, puis l&amp;#8217;éditer, puis le reconvertir en ISO-8859-1)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Les commentaires dans le code. Quand on commence à avoir un peu de bouteille comme moi, il est assez insupportable de lire des commentaires &quot;captain obvious&quot;, ce genre de commentaires qui dit &quot;la ligne suivante calcule 1+1&quot;. Claude en génère beaucoup. Trop. Et malgré le fait que mon fichier CLAUDE lui interdise explicitement.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;La confiance en soi. Claude est bien trop optimiste et tend trop à flatter l&amp;#8217;utilisateur. Par exemple, si je lui mens explicitement (&quot;ton algorithme est faux parce que XXX&quot;), il répondra systématiquement &quot;Tu as raison !&quot; sans &quot;réfléchir&quot; (j&amp;#8217;utilise les guillemets avec intention), comme un tic de langage ! Ca devient assez frustrant à la longue, lorsqu&amp;#8217;il ne comprend pas un problème ou complique inutilement l&amp;#8217;implémentation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Les limites : on arrive, sur un projet de la taille de JSol&amp;#8217;Ex, très rapidement aux limites d&amp;#8217;usage même sur un forfait Pro. Si je suis satisfait de ce que ça m&amp;#8217;apporte pour le prix, je ne suis pas prêt à payer les 200€ / mois pour augmenter ces limites. N&amp;#8217;oublions pas que je fais ça sur mon temps libre&amp;#8230;&amp;#8203; je n&amp;#8217;ai aucune obligation de résultat !&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Quoi qu&amp;#8217;il en soit, il s&amp;#8217;agit là d&amp;#8217;avancées qu&amp;#8217;il devient difficile d&amp;#8217;ignorer. Et ceux qui me connaissent savent à quel point je suis critique sur l&amp;#8217;utilisation des IA, les mythes autour de ce qu&amp;#8217;elle est capable de faire et son impact écologique. Néanmoins, une chose est certaine : les dirigeants qui pensent économiser du temps et de l&amp;#8217;argent en virant leurs développeurs pour les remplacer par de l&amp;#8217;IA se mettent une balle dans le pied : elle pose de sérieux problèmes de qualité de code et donc de maintenance, et, avec l&amp;#8217;arrivée des agents, posent de graves problèmes de sécurité (un outil autonome qui décide par lui même s&amp;#8217;il faut vous demander l&amp;#8217;autorisation pour exécuter une commande !&quot;). L&amp;#8217;IA doit être vue comme une aide à la productivité, mais qui doit être cadrée par des gens d&amp;#8217;expérience. Bref, nous sommes à un tournant et je ne suis pas encore bien à l&amp;#8217;aise avec ce que cela implique. Nous n&amp;#8217;avons jamais été aussi près du rêve de gosse que j&amp;#8217;avais d&amp;#8217;IA &quot;autonomes&quot;, mais la maturité me force à en avoir peur.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais nous nous éloignons là du sujet initial et concluons donc ce billet : dites bienvenue à JSol&amp;#8217;Ex 4, consultez la vidéo de présentation ci-dessous et n&amp;#8217;hésitez pas à contribuer !&lt;/p&gt;
&lt;/div&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/4SPKsNvnzKo?si=KuqIIMc1H6SLgVec&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Ellerman Bombs Detection with JSol&amp;#8217;Ex 3.2</title>
      <link>https://melix.github.io/blog//2025/05-19-jsolex-3-2-0.html</link>
      <pubDate>Sat, 17 May 2025 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2025/05-19-jsolex-3-2-0.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;style&gt;
.videoWrapper {
  position: relative;
  padding-bottom: 56.25%;
  /* 16:9 */
  padding-top: 25px;
  height: 0;
}

.videoWrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
&lt;/style&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_about_ellerman_bombs&quot;&gt;About Ellerman Bombs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ellerman bombs were first described by Ferdinand Ellerman back in 1917.
Ellerman&amp;#8217;s article was named -Solar Hydrogen &quot;Bombs&quot;- and it&amp;#8217;s only later that these were commonly referred to as &quot;Ellerman bombs&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I came upon this term while reading &lt;a href=&quot;http://www.astrosurf.com/rondi/obs/shg/Bombes_ellerman.htm&quot;&gt;an article from Sylvain or André Rondi&lt;/a&gt; quite early in my solar imaging journey, and I was since then obsessed by these phenomena.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ellerman Bombs are small, transient, and explosive events that occur in the solar atmosphere, particularly in the vicinity of sunspots.
These are very short lived compared to other solar features: from several dozens of seconds to a few minutes.
The most common explanation is magnetic reconnection, which occurs when two magnetic regions opposite polarity come into contact and reconnect, releasing energy in the form of heat and light.
This is for example described in &lt;a href=&quot;https://dx.doi.org/10.1051/0004-6361/201321632&quot;&gt;this article from González, Danilovic and Kneer&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Amateur observations of Ellerman bombs are quite rare, but Rondi described such observations using a spectroheliograph back in 2005.
They are rare because they are mostly invisible where the amateur observations are made (the center of the H-alpha line), and are too small to notice.
However, these are visible in the wings of the H-alpha line: this is where a spectroheliograph comes in handy, since the cropping window that is used to capture an image contains more than just the H-alpha line.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had a &lt;a href=&quot;https://github.com/melix/astro4j/issues/382&quot;&gt;long standing issue&lt;/a&gt; to do something about it in JSol&amp;#8217;Ex, and I finally got around to it: all it took was getting some test data to entertain the ideas.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_observation_of_an_ellerman_bomb&quot;&gt;Observation of an Ellerman Bomb&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am doing many observations of the sun: I started in 2023 with a Sol&amp;#8217;Ex, then I recently got an SHG 700, so I have accumulated quite a bit of data, which is completed by scans which are shared with me by other users of JSol&amp;#8217;Ex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have been looking for Ellerman bombs in my data, but I never found any yet.
This changed a couple weeks ago: I was doing some routine work on JSol&amp;#8217;Ex and using a capture I had done in April, 29, 2025 at 08:32 UTC, when I noticed, by accident, a bright spot in the continuum image:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/continuum.jpg&quot; alt=&quot;continuum&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It may not be obvious at first, which is precisely why these are hard to spot, so here&amp;#8217;s a hint:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/zoom-continuum.png&quot; alt=&quot;zoom continuum&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex offers the ability to easily generate animations of the data captured at different wavelengths, so I generated a quick animation, which shows the same image at ±2.5Å from the center of the H-alpha line:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/anim_ellerman.gif&quot; alt=&quot;anim ellerman&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can see the typical behavior of an Ellerman bomb: it is bright in the wings of the H-alpha line,  but it vanishes when we are at the center of the line.
The fine spectral dispersion of the spectroheliograph makes it possible to highlight this phenomenon very precisely.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The corresponding frame of the SER file shows the aspect of the Ellerman bomb in the spectrum:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/ellerman-spectrum.png&quot; alt=&quot;ellerman spectrum&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The shape that you can see is often referred to as the &quot;moustache&quot;.
At this stage I was pretty sure I had observed my first Ellerman bomb, and that I could implement an algorithm to detect it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_jsolex_3_2_auto_detection&quot;&gt;JSol&amp;#8217;Ex 3.2 auto-detection&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex 3.2 ships with a new feature to automatically detect Ellerman bombs in the data.
Currently, it is limited to H-alpha, but it should be possible to detect these in CaII as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The algorithm I implemented uses statistical analysis of the spectrum to match the characteristics of the &quot;moustache&quot; shape, in particular:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a maximum of intensity around 1Å from the center of the line&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a distance which spreads up to 5Å from the center of the line&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a brightening which is only visible in the wings of the line&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex will generate, for each detection, an image showing the location of the detected bombs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/ellerman-location.jpg&quot; alt=&quot;ellerman location&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And for each bomb, it will create an image which shows the region of the spectrum which is used to detect the bomb.
This is for example what is automatically generated for the bomb described above:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/spectrum-detection.jpg&quot; alt=&quot;spectrum detection&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_algorithm_details&quot;&gt;Algorithm details&lt;/h3&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
This is a description of the algorithm that I implemented in an &lt;em&gt;adhoc&lt;/em&gt; fashion: I&amp;#8217;m not a mathematician nor a scientist: I&amp;#8217;m an engineer and the algorithm above was implemented using my &quot;intuition&quot; of what I thought would work. It is likely to change as new versions are released.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The algorithm is based on the following steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;for each frame in the SER file, identify the &quot;borders&quot; of the sun&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;perform a Gaussian blur on the spectrum to reduce noise&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;within the borders, compute, for each column, the average intensity of the spectrum for the center of the line and the wings separately. The center of the line is defined as the range [-0.35Å, 0.35Å] and the wings as the range [-5Å, -0.35Å[ ∪ ]0.35Å, 5Å]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compute the maximum intensity of the wings, starting from the center of the line, and going outwards until we reach the maximum intensity (local extremum)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compute the average of each column average intensity for the wings (the &quot;global average&quot;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With Ellerman bomb scoring parameters defined below, the algorithm proceeds per column:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For each column index &lt;code&gt;x&lt;/code&gt; in the spectrum image:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build a neighborhood of up to 16 columns around &lt;code&gt;x&lt;/code&gt;:
&lt;code&gt;Nₓ = { x + k  |  k ∈ ℤ,  |k| ≤ 8 }&lt;/code&gt;, clamped to the image boundaries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compute the overall mean column intensity
&lt;code&gt;Ī_global = (1 / N_total) ∑_{j=1..N_total} Ī(j)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exclude any columns in &lt;code&gt;Nₓ&lt;/code&gt; whose average intensity falls below 90 % of &lt;code&gt;Ī_global&lt;/code&gt;, since very dark columns (usually sunspots) would pull down our estimate of the local wing background and hide true brightening events. Call the remaining set &lt;code&gt;Mₓ&lt;/code&gt; and let &lt;code&gt;m = |Mₓ|&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If &lt;code&gt;m &amp;lt; 1&lt;/code&gt;, there aren’t enough valid neighbors to form a reliable background—skip column &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the Gaussian-smoothed data, measure three key values at column &lt;code&gt;x&lt;/code&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;c₀ ≔ I_center(x)&lt;/code&gt;, the mean intensity in the core region of the spectral line.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;c_w ≔ I_wing(x)&lt;/code&gt;, the average intensity across the two wing windows at ±1 Å.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;c_max ≔ max_{p ∈ wing-pixels nearest ±1 Å} I(p, x)&lt;/code&gt;, the single highest wing intensity near the expected shift.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compute the local wing background
&lt;code&gt;r₀ = (1 / (m−1)) ∑_{j ∈ Mₓ, j≠x} I_wing(j)&lt;/code&gt;.
Using only nearby “bright enough” columns keeps the background estimate from being skewed by dark features.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Define a line-brightening factor
&lt;code&gt;B = max(1, c₀ / min(r₀, I_center,global))&lt;/code&gt;.
Ellerman bombs boost the wings without greatly brightening the core, whereas flares brighten both.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Form an initial score
&lt;code&gt;S₀ = 1 + c_max / min(r₀, I_wing,global)&lt;/code&gt;,
where &lt;code&gt;I_wing,global = (1/N_total) ∑_{j=1..N_total} I_wing(j)&lt;/code&gt;.
This compares the local wing peak to the typical wing level across the image.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adjust for how many neighbors were used:
&lt;code&gt;S₁ = S₀ × (m / 16)&lt;/code&gt;.
Fewer valid neighbors mean less confidence, so the score is scaled down proportionally.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compute the wing-to-background ratio
&lt;code&gt;rᵢ = c_max / r₀&lt;/code&gt;.
If &lt;code&gt;rᵢ ≤ 1.05&lt;/code&gt;, the wing peak is too close to the local background and the column is discarded. Otherwise, we boost the score further:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Raise &lt;code&gt;S₁&lt;/code&gt; to the power of &lt;code&gt;e^{rᵢ}&lt;/code&gt;, giving
&lt;code&gt;S₂ = S₁^( e^{rᵢ} )&lt;/code&gt;.
This makes the score grow quickly when the wing peak stands out strongly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multiply by &lt;code&gt;√(c_max / c₀)&lt;/code&gt; to get
&lt;code&gt;S₃ = S₂ · √(c_max / c₀)&lt;/code&gt;.
That emphasizes cases where the wings are much brighter than the core.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, penalize any shift away from the ideal ±1 Å wing position. If &lt;code&gt;y_core&lt;/code&gt; and &lt;code&gt;y_max&lt;/code&gt; are the pixel locations of line center and wing peak, compute
&lt;code&gt;Δλ = |y_max – y_core| × (Å / pixel)&lt;/code&gt;,
then
&lt;code&gt;S_final = S₃ / (1 + |1 Å – Δλ|)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If &lt;code&gt;S_final &amp;gt; 12&lt;/code&gt;, mark column &lt;code&gt;x&lt;/code&gt; as a candidate event. Use the value of &lt;code&gt;B&lt;/code&gt; to decide:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When &lt;code&gt;B &amp;lt; 1.5&lt;/code&gt;, it behaves like an Ellerman bomb (wings bright, core unchanged).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When &lt;code&gt;B &amp;gt; 2&lt;/code&gt;, it matches a flare (both core and wings bright).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If &lt;code&gt;1.5 ≤ B ≤ 2&lt;/code&gt;, the result is ambiguous and ignored.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All thresholds (0.9× global mean, 1.05 ratio, score &amp;gt; 12, B cutoffs) were chosen by testing on data and visually inspecting results.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_post_filtering&quot;&gt;Post-filtering&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There will often be cases where the same bomb is detected in multiple frames.
Therefore, we need to do some merging of bombs which are spatially connected.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, we apply a limit threshold: if there are more than 5 Ellerman Bombs detected in an image, then we consider the detection to be false positives (this happens typically on saturated images, or images with too much noise).
This is a bit arbitrary, but it seems to work well in practice.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_test_data&quot;&gt;Test data&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had about ~1100 scans I could reuse for detection, and it successfully discovered Ellerman bombs candidates in about 10% of them.
Of course this required some tuning and several runs to get the parameters right.
This doesn&amp;#8217;t mean that you have 10% chances of finding an Ellerman bomb in your data, because the test data I have is biased (I often do 10 to 20 scans in a row, within a few minutes, to perform stacking, so if a bomb is detected in an image, it has decent chances of being detected in the next one).
Also, I am using the term &quot;Ellerman Bomb candidate&quot;, because there&amp;#8217;s nothing better than visual confirmation to make sure that what you see is indeed an Ellerman bomb: an algorithm is not perfect, and it may fail for many reasons (noise, saturation, artifacts, etc.)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are a few examples of Ellerman bombs candidates detected in my data:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate1.jpg&quot; alt=&quot;candidate1&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate2.jpg&quot; alt=&quot;candidate2&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate3.jpg&quot; alt=&quot;candidate3&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate4.jpg&quot; alt=&quot;candidate4&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate5.jpg&quot; alt=&quot;candidate5&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/ellerman/candidate6.jpg&quot; alt=&quot;candidate6&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This blog post described my first visual Ellerman bomb detection.
Then I described how I implemented an algorithm to automatically detect Ellerman bombs in JSol&amp;#8217;Ex 3.2.
I am very happy to release this to the wild, so that this kind of discovery is made more accessible to everyone.
Of course, as I always say, you should take the detections with care, and always review the results.
This is why you get both a global &quot;map&quot; of the detected bombs, and a detailed view of each bomb, which can be used to confirm the detection.
In addition, I recommend that you create animations of the regions, which you can simply do in JSol&amp;#8217;Ex by CTLR+clicking on the image then selecting an area around the bomb.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finally, I&amp;#8217;d like to thank my friends of the Astro Club de Challans, who heard me talk about Ellerman bombs detection for a while, showing them preliminary results, and who were very supportive of my work.
Last but not least, thanks again to my wife for her patience, seeing me work on this (too) late at night!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_bibiography&quot;&gt;Bibiography&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://ui.adsabs.harvard.edu/abs/1917ApJ&amp;#8230;&amp;#8203;.46..298E/abstract&quot;&gt;Ellerman, F. (1917) - Solar Hydrogen &quot;Bombs&quot;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.astrosurf.com/rondi/obs/shg/Bombes_ellerman.htm&quot;&gt;S. Rondi, A. Rondi - Bombes d&amp;#8217;Ellerman&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://dx.doi.org/10.1051/0004-6361/201321632&quot;&gt;N. Bello González , S. Danilovic , and F. Kneer - On the structure and dynamics of Ellerman bombs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jstage.jst.go.jp/article/starsandgalaxies/6/0/6_3/_article/-char/en&quot;&gt;R. Ichikawa, S. Nozawa - Detailed altitude analysis of Ellerman bomb using the domeless solar telescope at the Hida Observatory, Kyoto University&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1407.3048&quot;&gt;Jie Hong, M. D. Ding, Ying Li, Cheng Fang, Wenda Cao - Spectral observations of Ellerman bombs and fitting with a two-cloud model&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/abs/1406.5702&quot;&gt;A. Berlicki, P. Heinzel - Observations and NLTE modeling of Ellerman bombs&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://adsabs.harvard.edu/full/2007ASPC..368..253P&quot;&gt;E. Pariat, B. Schmieder, A. Berlicki., A. López Ariste - Spectrophotometry of Ellerman Bombs with THEMIS&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Jagged Edges Correction with JSol&amp;#8217;Ex 3.1</title>
      <link>https://melix.github.io/blog//2025/05-02-jsolex-3-1-0.html</link>
      <pubDate>Fri, 2 May 2025 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2025/05-02-jsolex-3-1-0.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;style&gt;
.videoWrapper {
  position: relative;
  padding-bottom: 56.25%;
  /* 16:9 */
  padding-top: 25px;
  height: 0;
}

.videoWrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
&lt;/style&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m happy to announce the release of JSol&amp;#8217;Ex 3.1, which ships with a long awaited feature: jagged edges correction! Let&amp;#8217;s explore in this article what this is about.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_dreaded_jagged_edges&quot;&gt;The dreaded jagged edges&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Spectroheliographs like the Sol&amp;#8217;Ex or the Sunscan are not using a traditional imaging system like, for example, in planetary imaging, where you can capture dozens to hundreds of frames per second and do the so called &quot;lucky imaging&quot; to get the best frames and stack them together to get a high resolution image.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the case of a spectroheliograph, the image is built by scanning the solar disk in a series of &quot;slices&quot; of the sun: it takes several seconds and sometimes minutes (~3 minutes when you let the sun pass &quot;naturally&quot; through the slit) to get a full image of the sun.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In practice, this means that between each frame, each &quot;slice&quot; of the sun, the atmosphere will have slightly moved, causing some misalignment between the frames.
This is also particularly visible when there is some wind, which can cause the telescope to shake a bit, and the image to be misaligned.
Lastly, you may even have a mount which is not perfectly balanced, or which has some resonance at certain scan speeds.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an illustration, let&amp;#8217;s take this image captured using a Sunscan (courtesy of Oscar Canales):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex_3_1/original.jpg&quot; alt=&quot;original&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This image shows 3 problems:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;the jagged edges, which cause some unpleasant &quot;spikes&quot; on the edges of the sun&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;misalignment of features of the sun, particularly visible on filaments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a disk which isn&amp;#8217;t perfectly round&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;These issues are typical of spectroheliographs, and are the main limiting factor when it comes to achieving high resolution images.
Therefore, excellent seeing conditions are a must to get high quality images.
Even if you do stacking, the fact that the reference image will show spikes is often a problem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_correcting_jagged_edges&quot;&gt;Correcting jagged edges&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Starting with release 3.1.0, JSol&amp;#8217;Ex ships with an &lt;strong&gt;experimental&lt;/strong&gt; feature to correct jagged edges.
It is not perfect yet, but good enough for you to provide feedback and even improve the quality of your images.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, here&amp;#8217;s the same image, but with jagged edges correction applied:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex_3_1/corrected.jpg&quot; alt=&quot;corrected&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And so that it&amp;#8217;s even easier to see the difference, here&amp;#8217;s a blinking animation of the two images:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex_3_1/blink.gif&quot; alt=&quot;blink&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The jagged edges are now mostly gone, the features in the sun are better aligned, and the image is much more pleasant to look at.
There is still some jagging visible, the correction will never be perfect, but it is a good start.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, you should be careful when applying the correction, because it could cause some artifacts in the image, in particular on prominences.
As usual, with great powers comes great responsibilities!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_does_it_work&quot;&gt;How does it work?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To illustrate how the correction works, let&amp;#8217;s imagine a perfect scan: a scan speed giving us a perfectly circular disk, no turbulence, no wind, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, what we would see during the scan is a spectrum which width slowly increases, reaches a maximum, and then decreases.
The pace at which the width increases and decreases is determined by the scan speed and is predictable.
In particular, the left and right borders of the spectrum will follow a circular curve.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, let&amp;#8217;s get back to a &quot;real world&quot; scan.
In that case, the left and right edges will slightly deviate from the circular curve.
They will also follow the path of an ellipse: in fact, this ellipse is already required in order to perform geometric correction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea is therefore quite simple in theory: we need to detect the left and right edges of the spectrum, then compare them to the ideal ellipse that we have computed.
Pixels which deviate from this curve give us an information about the jagged edges.
We can then compute a distortion map, which will be used to correct the image.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In practice, we also need to apply some filtering of samples: in practice, while the detection of edges is robust enough to provide us with a good geometric correction, it is not perfect.
It can also be skewed by the presence of proms for example.
Therefore, we are performing a sigma clipping on the detected edges, in order to remove outliers, that is to say pixels which deviate too much from the average deviation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is also why the correction will not work properly if the image is not focused correctly: you would combine two problems in one, and the correction would not be able to detect the edges properly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, in the image above you can see that the bottom most prominence is slightly distorted, which is caused by the fact that it&amp;#8217;s far away from the 2 points which were used to compute the distortion.
It may be possible to reduce such artifacts by using a smaller sigma factor (at the risk of undercorrecting edges).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, I have described the new jagged edges correction feature in JSol&amp;#8217;Ex 3.1.
This solves one of the most common issues users are having with spectroheliographs, and I hope it will help you get better images.
However, as usual, it&amp;#8217;s a work in progress, so do not hesitate to provide feedback!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JSol&amp;#8217;Ex 3.0.0 is out!</title>
      <link>https://melix.github.io/blog//2025/04-14-jsolex-3-0-0.html</link>
      <pubDate>Mon, 14 Apr 2025 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2025/04-14-jsolex-3-0-0.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;style&gt;
.videoWrapper {
  position: relative;
  padding-bottom: 56.25%;
  /* 16:9 */
  padding-top: 25px;
  height: 0;
}

.videoWrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
&lt;/style&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After dozens of hours of work, I&amp;#8217;m happy to announce the release of JSol&amp;#8217;Ex 3.0.0!
This major release is a new milestone in the development of JSol&amp;#8217;Ex, and it brings new features and improvements that I hope you will enjoy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_bit_of_history&quot;&gt;A bit of history&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since its inception as an educational project for understanding how the Sol&amp;#8217;Ex works, JSol&amp;#8217;Ex has grown into a powerful tool for processing and analyzing images captured with the Sol&amp;#8217;Ex.
However, it became very popular over time and started to be used outside the sole Sol&amp;#8217;Ex community.
In particular, it is now a tool of choice for many spectroheliographs owners.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have always been keen on providing a user-friendly interface while keeping a good innovation pace.
JSol&amp;#8217;Ex was the first SHG software to offer:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;automatic colorization of images&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic detection of spectral lines&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Doppler eclipse image, inverted image and orientation grid&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic correction of the P angle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;single click processing of Helium line images&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;embedded stacking&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic trimming and compression of SER files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;identifying what frame of a SER file matches a particular point of the solar disk&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an optimal exposure calculator&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic detection of redshifts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic detection and annotation of sunspots&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;automatic creation of animations of a single image taken at different wavelengths&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a full-fledged scripting engine which allows creation of custom images, animations, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;support for home-made SHGs&lt;/p&gt;
&lt;div class=&quot;olist lowerroman&quot;&gt;
&lt;ol class=&quot;lowerroman&quot; type=&quot;i&quot;&gt;
&lt;li&gt;
&lt;p&gt;and more!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All integrated into a single, easy to use, cross-platform application: no need for Gimp, ImPPG or Autostakkert! (but you can use them if you want to!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For this new release, I wondered if I should &lt;a href=&quot;https://github.com/melix/astro4j/issues/502&quot;&gt;change the name&lt;/a&gt; so that it better matches the new scope of the project, but eventually decided to keep it as it is, because it is already well known in the community and that changing it also implies significant amount of time spent on this that wouldn&amp;#8217;t go into the new features.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_here_comes_jsolex_3_0_0&quot;&gt;Here comes JSol&amp;#8217;Ex 3.0.0!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition to performance improvements and bugfixes, this release deserves its major version number because of many significant improvements.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;videoWrapper&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/9mU_8j3lNcg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_improved_image_quality&quot;&gt;Improved image quality&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_better_line_detection&quot;&gt;Better line detection&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first thing you may notice is the improved image quality.
The algorithm to detect the spectral lines have been improved, which will result in a better polynomial detection and therefore a more accurate image reconstruction.
This will be noticeable in images which have low signal, which is often the case in calcium.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_background_removal&quot;&gt;Background removal&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Next, a new background removal algorithm has been added.
It is fairly common to have either internal reflections or light leaks in the optical path of a spectroheliograph.
This results in images which are hard to process or not usable at all.
This version of JSol&amp;#8217;Ex is capable of removing difficult gradients.
To illustrate this, here&amp;#8217;s an image that a user with a Sunscan sent me:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex3/sunscan_ca_bg.jpg&quot; alt=&quot;sunscan ca bg&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The image on the left is &lt;em&gt;unprocessed&lt;/em&gt; and shows important internal reflections.
These are completely removed in the image on the right, processed automatically with JSol&amp;#8217;Ex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This background removal will only be applied to the &quot;Autostretch&quot; image, which is the default &quot;enhanced&quot; image that JSol&amp;#8217;Ex is using, but it is also available as a standalone function in ImageMath scripts.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_physical_flat_correction&quot;&gt;Physical flat correction&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another common issue with SHGs is the presence of vignetting, visible on the poles of the solar disk.
The vignetting issue stems from the following factors, in the order of their impact:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the physical size of the SHG’s optical components — including the lens diameter, grating size, and slit length&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the telescope’s focal ratio and focal length&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the telescope’s own intrinsic vignetting (though this is rarely a significant factor)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For prebuilt SHGs like the MLAstro SHG 700, the size of the lens and grating is typically constrained by the housing design and cost limitations.
As a result, vignetting often becomes an issue when using longer focal length telescopes,—especially when paired with a longer slit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To fix this, JSol&amp;#8217;Ex had until now the option to use artificial flat correction: the idea was basicaly to model the illumination of the solar disk via a polynomial and to apply a correction to the image.
This works relatively well, but it can sometimes introduce some noise, or even bias the reconstruction on low-contrast images.
On even longer slits, this artificial correction is not sufficient to remove the vignetting, so JSol&amp;#8217;Ex 3 introduces the ability to use a &lt;strong&gt;physical flat correction&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea with a physical flat correction is to take a series of 10 to 20 images of the sun, using a light diffuser device at the entrance of the telescope, such as tracing paper, in order to diffuse light.
The flat should be captured with the same cropping window as the one used for the solar images, but exposure will be longer, and possibly higher gain as well.
The result is a SER file that JSol&amp;#8217;Ex can use to create a model of the illumination of the disk, which can be used to correct the images.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an illustration, here&amp;#8217;s a series of 3 images of the Sun, taken with a prototype of a 10mm slit:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex3/flat_correction.jpg&quot; alt=&quot;flat correction&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The image on the left is done without any correction and shows very strong vignetting.
The image in the middle is done with the artificial flat correction, improves the situation, but still shows some vignetting.
The image on the right is done with the physical flat correction, which is much better and shows no vignetting at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Flats can be reused between sessions, as long as you use the same cropping window and the same wavelength.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The physical flat correction can also be used on images taken with a Sol&amp;#8217;Ex, in particular for some wavelengths like H-beta which show stronger illumination of the middle of the solar disk.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Flat correction is not designed to fix transversalliums: it has to apply low pass filtering to the image to compute a good flat, which will remove the transverse lines.
To correct transversalliums, use the banding correction parameters.&lt;/p&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_new_stretching_options&quot;&gt;New Stretching Options&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, JSol&amp;#8217;Ex used to display images applying a linear stretch.
Starting with this version, it is possible to select which stretching algorithm to use: linear, curve or no stretching at all.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex3/stretching.jpg&quot; alt=&quot;stretching&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_distance_measurement_tool&quot;&gt;Distance measurement tool&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This version introduces a new tool to measure distances!
This feature was suggested by Minh Nguyen from &lt;a href=&quot;https://mlastro.com/&quot;&gt;MLAstro&lt;/a&gt;, after seeing one of my images in Calcium H, which showed a very long filament:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex3/open-measure.jpg&quot; alt=&quot;open measure&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This tool lets you click on waypoints to follow a path and make measurements on the disk, in which case the distances take the curvature into account, or outside the disk, for example to measure the size of prominences, in which case the distances are linear.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex3/measurements.jpg&quot; alt=&quot;measurements&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The measured distances are always an approximation, because it&amp;#8217;s basically impossible to know at what height a particular feature is located, but it gives a good rough estimate.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_new_scripting_features&quot;&gt;New scripting features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, this version significantly improves the scripting engine, aka ImageMath.
While this feature is for more advanced users, it is an extremely powerful tool which lets you generate custom images, automatically stack images, create animations, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this version, the scripting engine has been rewritten to make it more enjoyable to use.
It adds:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the ability to write expressions on several lines&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the possibility to use named parameters&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the ability to define your own functions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;call an external web service to generate script snippets&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the ability to import scripts into other scripts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As well as new functions.
Let&amp;#8217;s take a deeper look.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_declaring_your_own_functions&quot;&gt;Declaring your own functions&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You may have faced the situation where you wanted to apply the same operation to several images.
For example, let&amp;#8217;s imagine that you want to decorate an image with the observation details and the solar parameters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before, you would write something like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;image1=draw_solar_params(draw_obs_details(some_image)
image2=draw_solar_params(draw_obs_details(some_other_image)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, you can define a function, let&amp;#8217;s call it &lt;code&gt;decorate&lt;/code&gt;, which will take an image and return the decorated image:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;[fun:decorate img]
    result = draw_solar_params(draw_obs_details(img))

[outputs]
image1=decorate(some_image)
image2=decorate(some_other_image)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can take a look at the &lt;a href=&quot;https://melix.github.io/astro4j/3.0.0/en/jsolex.html#custom-functions&quot;&gt;documentation&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_importing_scripts&quot;&gt;Importing scripts&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the previous section we have seen how to define functions.
It can be useful to externalize these functions in a separate file, so that they can be reused in other scripts.
This is now possible with the &lt;code&gt;import&lt;/code&gt; statement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, let&amp;#8217;s say you have a file called &lt;code&gt;utils.math&lt;/code&gt; which contains the &lt;code&gt;decorate&lt;/code&gt; function.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can now import this file in our script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;[include &quot;utils&quot;]

[outputs]
image1=decorate(some_image)
image2=decorate(some_other_image)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This will import the &lt;code&gt;utils.math&lt;/code&gt; file and make the &lt;code&gt;decorate&lt;/code&gt; function available in the current script.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_named_parameters&quot;&gt;Named parameters&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Named parameters are a new feature that allows you to pass parameters to functions by name, instead of by position.
This is particularly useful for functions that take a lot of parameters, or when you want to make your code more readable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, in the example above, we could have written:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;[include &quot;utils&quot;]

[outputs]
image1=decorate(img: some_image)
image2=decorate(img: some_other_image)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The names of the parameters are &lt;a href=&quot;https://melix.github.io/astro4j/3.0.0/en/jsolex.html#_functions_available_in_imagemath&quot;&gt;documented here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_new_functions&quot;&gt;New functions&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This version introduces a few new functions, which are available in the scripting engine:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bg_model&lt;/code&gt;: background sky modeling&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;a2px&lt;/code&gt; and &lt;code&gt;px2a&lt;/code&gt;: conversion between pixels and Angstroms&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;wavelen&lt;/code&gt;: returns the wavelength of an image, based on its pixel shift, dispersion, and reference wavelength&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;remote_scriptgen&lt;/code&gt;: allows calling an external web service to generate a script or images&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;transition&lt;/code&gt;: creates a transition between two or more images&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;curve_transform&lt;/code&gt;: applies a transformation to the image based on a curve&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;equalize&lt;/code&gt;: equalizes the histograms of a series of images so that they look similar in brightness and contrast&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And others have been improved:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;find_shift&lt;/code&gt;: added an optional parameter for the reference wavelength&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;continuum&lt;/code&gt;: improved function reliability, enhancing Helium line extraction&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;transition&lt;/code&gt; function, for example, is capable of generating intermediate frames in an animation, based on the actual difference of time between two images, offering the ability to have smooth, uniform transitions between images.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is how my &lt;a href=&quot;https://melix.github.io/blog/2025/03-30-partial-eclipse.html&quot;&gt;partial solar eclipse&lt;/a&gt; animation was created!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_acknowledgements&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I would like to thank all the users who have contributed to this release by reporting bugs, suggesting features, and testing the software.
In particular, I would like to recognize the following people:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Minh Nguyen, &lt;a href=&quot;https://mlastro.com/&quot;&gt;MLAstro&amp;#8217;s founder&lt;/a&gt; for his help with the background removal and flat correction algorithms, as well as the new distance measurement tool and review of this blog post&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yves Robin for his testing and improvement ideas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;my wife for her patience, while I was going to bed late every night to work on this release&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Partial Eclipse of March 29, 2025</title>
      <link>https://melix.github.io/blog//2025/03-30-partial-eclipse.html</link>
      <pubDate>Sun, 30 Mar 2025 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2025/03-30-partial-eclipse.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;style&gt;
.videoWrapper {
  position: relative;
  padding-bottom: 56.25%;
  /* 16:9 */
  padding-top: 25px;
  height: 0;
}

.videoWrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
&lt;/style&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post I&amp;#8217;m describing what is probably a world premiere (let me know if not!): capturing a partial solar eclipse using a spectroheliograph and making an animation which covers the whole event.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Edit: Turns out Olivier Aguerre did something similar, described &lt;a href=&quot;http://www.astrosurf.com/topic/175255-eclipse-partielle-du-2903-en-ha-et-continuum-avec-soles/&quot;&gt;here (french)&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_preparations&quot;&gt;Preparations&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On March 29, 2025, we were lucky to get a partial solar eclipse visible in France, with a maximum of about 25%.
I wanted to do what was a first for me, capturing the event, so I used a TS-Optics 80mm refractor with a 560mm focal length, equipped with an MLAstro SHG 700 spectroheliograph.
The Astro Club Challandais was organizing a group observation this morning, but my initial decision was not to attend.
Instead, I opted to limit the risks by performing this somewhat complex setup at home, in familiar territory. Unlike the SUNSCAN, using a spectroheliograph like the SHG 700 requires more equipment: a telescope, a mount (AZ-EQ6), and in my case, a mini PC for data acquisition (running Windows) along with a laptop for remote connection to the PC.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have conducted observations away from home before, but from experience, setting everything up—including WiFi, polar alignment, etc.—can be a bit too risky for an event like this.
So, all week, I anxiously monitored the weather.
Yesterday, the forecast looked grim, with thick clouds and rain.
However, the gods of astronomy were merciful, blessing us with a beautiful day.
The sky wasn’t entirely clear, but it was good enough for observations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_some_more_context&quot;&gt;Some more context&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, I had a specific observation protocol in mind.
As you may know, a spectroheliograph doesn’t directly produce an image—it requires software to process video scans of the Sun.
In the case of the Sunscan, the software is built into the device, but for a Sol’Ex-type setup, an independent software handles this task.
You are probably familiar with INTI, but I have my own software: &lt;a href=&quot;https://melix.github.io/astro4j/latest/en/jsolex.html&quot;&gt;JSol’Ex&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The advantage of developing my own software is that I was able to anticipate potential issues.
One major challenge with an eclipse is that the software must &quot;recognize&quot; the Sun&amp;#8217;s outline, which won’t always be perfectly round—in fact, it could be quite elliptical.
The software corrects the image by detecting the edges, but when the Moon moves in front, the sampling points become completely incorrect, sometimes detecting the lunar limb instead of the Sun’s!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My strategy was to start early enough to adjust settings for minimal camera tilt and, more importantly, to ensure an X/Y ratio of 1.0.
With these reference scans, I could then force all subsequent scans to use the same parameters.
So, I began my first scans under a beautifully clear sky! After some adjustments, I was ready: a single scan, and we were good to go!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/09_45_53_0000_09_45_53_autostretch_0_00.jpg&quot; alt=&quot;09 45 53 0000 09 45 53 autostretch 0 00&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the same time, I activated JSol’Ex’s integrated web server and set up a tunnel so my friends could watch my observations live! I planned to perform a scan every two minutes using a Python script in SharpCap, automating the recording, scan start, stop, and rewind. JSol’Ex’s &quot;continuous&quot; mode processed scans in real time.
Everything was going smoothly&amp;#8230;&amp;#8203; until panic struck—clouds!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the past three hours, the sky had been perfectly clear. Yet, just ten minutes before the eclipse began, clouds started rolling in.
What bad luck! Fortunately, by spacing out the scans, I managed to capture many of them in cloud-free moments.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/clouds.jpg&quot; alt=&quot;clouds&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The eclipse began, and the first scans featuring the Moon appeared.
It worked! Forcing the X/Y ratio was effective!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/begin-eclipse.jpg&quot; alt=&quot;begin eclipse&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As the scans piled up, I encountered a new problem.
While locking the X/Y ratio helped, the software still needed to calculate an ellipse to determine the Sun’s center for cropping.
But things started going wrong—the software was miscalculating everything. I had anticipated this, and I already had a workaround in mind, but the necessary code wasn’t deployed on my mini PC.
So, I didn&amp;#8217;t worry too much and simply shared the raw images, which were perfectly round—because, as you recall, I had already adjusted my X/Y ratio to 1.0!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I continued scanning, though my setup wasn&amp;#8217;t perfectly precise.
My polar alignment wasn’t flawless, and I had no millimeter-accurate return-to-start positioning.
As a result, I had to manually realign between each scan.
While this wasn’t a major issue, it did create some intriguing scans. For those familiar with Sol’Ex, seeing &quot;gaps&quot; in the spectrum due to the Moon’s presence was quite unusual, making centering more difficult.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/anim.gif&quot; alt=&quot;anim&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_eclipse_reaches_maximum&quot;&gt;The eclipse reaches maximum&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Time passed, scans continued, and finally, we reached the maximum eclipse phase!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/max-mono.jpg&quot; alt=&quot;max mono&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/max-mix.jpg&quot; alt=&quot;max mix&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At one point, I wondered whether we could see lunar relief in the images.
However, given the jagged edges typical of SHG imaging, it was hard to say for sure, but, I think some of the details visible below are actual surface details.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/eclipse/crop.jpg&quot; alt=&quot;crop&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_end_of_observation&quot;&gt;End of observation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By the end of the eclipse, I had 80 SER files, taken between 9:37 AM and 1:43 PM, totaling nearly 175 GB of data!
It was time to transfer everything to my desktop PC to create an animation.
This also gave me a chance to test whether my earlier workarounds for ellipse detection would function as expected.
I ran batch processing, and boom—within minutes, I had this animation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;videoWrapper&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/1C8CCPQnedM&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And here’s the continuum version which was weirdly compressed by Youtube:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;videoWrapper&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/C_qJnSaSpaU&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This was just a first draft, using a beta version of my software.
A few hours later I released a new version of the animation which is visible below:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;videoWrapper&quot;&gt;
&lt;iframe src=&quot;https://www.youtube.com/embed/hAcHwbWDiW0&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, the experiment was a success! I also took this opportunity to improve my software, which will benefit everyone. If you have eclipse scans, don’t discard them! Soon, you’ll be able to process them too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The big question now is: Could this be done during a total solar eclipse, such as next year&amp;#8217;s in Spain?
Well, I feel lucky that this one was only 25% partial.
Managing ellipse detection and mount realignment between scans is already quite tricky.
During a total eclipse, there wouldn’t even be a reference point!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Unless one has flawless alignment, a mount capable of returning to position perfectly, and a steady scanning speed, this would be a real challenge.
Honestly, it&amp;#8217;s beyond my current expertise—it would require a lot more work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;P.S: For french speaking readers in west of France (or simply if you are nearby at that date), we organize the &lt;a href=&quot;https://astroclubchallanda.wixsite.com/website/rsv&quot;&gt;Rencontres Solaires de Vendée&lt;/a&gt; on June 7, where we can discuss this topic!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JSol&amp;#8217;Ex errands: How it helped uncovering an inaccuracy of the SHG 700 specifications</title>
      <link>https://melix.github.io/blog//2025/03-11-jsolex-shg700.html</link>
      <pubDate>Tue, 11 Mar 2025 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2025/03-11-jsolex-shg700.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For a few months, I&amp;#8217;ve been working with Minh, from MLAstro, to improve support of the &lt;a href=&quot;https://mlastro.com/mlastro-shg&quot;&gt;SHG 700&lt;/a&gt; in JSol&amp;#8217;Ex.
While JSol&amp;#8217;Ex was initially designed for &lt;a href=&quot;https://solex.astrosurf.com/sol-ex-presentation-en.html&quot;&gt;Christian Buil&amp;#8217;s Sol&amp;#8217;Ex&lt;/a&gt;, it appears that lots of users are using it to process images acquired using a different spectroheliograph.
A while back, I added the ability to declare the specifications of the spectroheliograph you are using, which makes JSol&amp;#8217;Ex compatible with a wide variety of instruments.
An example of collaboration with Minh is the experimental flat correction, which is recommended to enable with the SHG 700, and the addition of the SHG 700 to the list of instruments which are officially supported, in addition to the Sol&amp;#8217;Ex and the &lt;a href=&quot;https://www.sunscan.net/&quot;&gt;Sunscan&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_first_light_with_shg_700&quot;&gt;First light with SHG 700&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, I had been working with MLAstro for quite some time already, but I didn&amp;#8217;t own the instrument.
This has recently been &quot;fixed&quot; and I&amp;#8217;m now a happy user of the SHG 700!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I must say that Minh&amp;#8217;s design is fairly impressive, it&amp;#8217;s a truly qualitative instrument.
The aluminum housing makes it extremely robust, without any flexion, and it comes pre-collimated.
In addition, the micro-focusers, which are used for the collimator lens, for the camera objective and for the wavelength selection wheel, are extremely pleasant to use: anyone who has struggled with the collimation of the Sol&amp;#8217;Ex will immediately feel the magic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Being a regular user of the Sol&amp;#8217;Ex, I immediately felt comfortable with the SHG 700: it only took me a few minutes to setup and get my first images!
Fine tuning the focus is a breeze with the microfocusers, it&amp;#8217;s really fantastic to use.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My first images were showcased by MLAStro, but here are a few:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/13_10_48_0000_ha_batch.jpg&quot; alt=&quot;13 10 48 0000 ha batch&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/CaK.jpg&quot; alt=&quot;CaK&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/20250503-Hb.jpg&quot; alt=&quot;20250503 Hb&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/20250503-Mg-b1.jpg&quot; alt=&quot;20250503 Mg b1&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/20250307-animation-Ha-inv.gif&quot; alt=&quot;20250307 animation Ha inv&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_mystery&quot;&gt;A mystery&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While the above images were fairly easy to produce, I was puzzled because I didn&amp;#8217;t manage to get any decent image in Helium D3.
This was surprising, because the sensitivity of the SHG700 is higher, especially because there&amp;#8217;s no need for a ND filter or a an ERF, so it was curious that the only helium image I was able to produce was this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/helium-error.jpg&quot; alt=&quot;helium error&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To understand the problem was that, it is important to mention that unlike Minh, I was using JSol&amp;#8217;Ex &lt;a href=&quot;http://localhost:8820/blog/2024/06-14-jsolex-helium-continuum.html&quot;&gt;one-click, fully automated processing&lt;/a&gt;, a feature which was introduced a while ago (June 2024) and worked extremely well for both Sol&amp;#8217;Ex and Sunscan files (N.B: the Sunscan app introduced the same feature a few days ago).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This feature only works if we can properly compute the dispersion of the spectrum, which is measured in Angstrom/pixel.
In order to compute this, we need to know the specifications of the spectroheliograph, such as the grating density, the focal length of the collimator and objective lenses, the total angle as well as the pixel size of the camera.
Once we know all this, we can determine how many pixels separate the reference line that we use, for example the Sodium D2 line, from the Helium D3 line.
To illustrate this, let&amp;#8217;s say that we have a dispersion of 0.1Å/px. The Helium line is to be found at 5875.62Å, when the reference line, the Sodium D2 line, is detected at 5889.95Å.
Therefore, the Helium line can be found 14.33Å away from the D2 line, which means 14.33/0.1 = 143.3 pixels away.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using both Sol&amp;#8217;Ex and Sunscan, I had great experience at extracting this line automatically, so it was to say the least curious that it wouldn&amp;#8217;t work with the SHG 700.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_investigation&quot;&gt;Investigation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I contacted Minh, and after eliminating obvious possible candidates, like weak signal or incorrect exposition or gain, I decided to go the &quot;old way&quot; and searched for the helium line manually.
It was with great surprise that I discovered that when JSol&amp;#8217;Ex told me that the line should be 124.9, I was measuring something closer to 116 pixels!
I brought this to Minh, and we identified 3 possible causes for this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;an error in the computation of the dispersion in JSol&amp;#8217;Ex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a different focal length of the SHG 700&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a grating which wouldn&amp;#8217;t have the expected number of lines/mm&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was also possible, but unlikely, that a combination of 2 and 3 would happen.
The first thing I&amp;#8217;ve done is double checking my formula to compute the dispersion in JSol&amp;#8217;Ex.
I was doubtful that it could be wrong, given that it was used with success on different SHGs.
In addition, it gave exactly the same result as the &lt;a href=&quot;https://solarchatforum.com/viewtopic.php?t=48072&quot;&gt;Ken Harrison&apos; SimSpec SHG spreadsheet&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So we moved to the 2d option: the SHG 700 was advertised with a focal length of 75mm.
However, the pixel shift I was manually measuring was closer to 70mm.
I brought this again to Minh, who contacted the supplier of the lens, and here&amp;#8217;s what he told me:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The lens from the first production run had a focal length of 72mm, a discrepancy I was unaware of at the time. I had sourced this lens from a supplier in China and provided them with the Zemax file for my self-designed 6-element Double Gauss 75mm lens. The first prototype was disappointing—its near-UV performance and coating were poor, and contrast was low across the field. This was largely due to my inexperience in optical design, as I had only begun learning Zemax a month prior, making this my first optical project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I raised these concerns with the supplier, who was very accommodating and offered to help optimize the design while ensuring key parameters such as focal length, aperture, and exit pupil remained unchanged. With each revision, the lens improved—by the second and third prototypes, contrast was significantly better, sharpness in the blue end of the spectrum improved, and the field was much flatter across the FOV. The field of view closely matched the earlier lens, and because I had already tested focal length in previous iterations, I didn’t think to recheck it. Visually, the lenses appeared identical, except for a slight shift in coating hue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;The third prototype was approved for production and became the MLAstro &quot;75mm&quot; compound lens used in all MLAstro SHGs. However, it was only later confirmed by the supplier that the final production lens actually had a focal length of 72mm instead of 75mm&lt;/strong&gt;. The optimizations for blue performance and field flattening had slightly shortened the focal length.&quot;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; Mihn Truong Nguyen&lt;br&gt;
&lt;cite&gt;MLAstro&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I changed the focal length to 72mm and got this image instead:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/helium-fixed.jpg&quot; alt=&quot;helium fixed&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and a stack of 5 images processed entirely in JSol&amp;#8217;Ex:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/helium-stacked.jpg&quot; alt=&quot;helium stacked&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s quite a difference! So it appeared that the software was correct, and that it allowed identifying a problem in the spectrograph specifications, because a spectral line wasn&amp;#8217;t found where it should have been!
While going from 75mm to 72mm won&amp;#8217;t make much of a difference, the fact of not using the right numbers makes a huge difference in JSol&amp;#8217;Ex: computations are all off, which includes the pixel shifts like in this exercise, but also the measured redshifts.
In addition, this would make it impossible to perform more complicated tasks like finding the ionized Fe lines when imaging the corona E.
The image is stil less contrasted than it should be, which may indicate that the computation is slightly off, or it&amp;#8217;s just due to the weather conditions that day, I didn&amp;#8217;t have the opportunity to retry.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lastly, we can actually see fairly easily that the new focal length is a better fit, by using JSol&amp;#8217;Ex &quot;profile&quot; tab.
In that tab, we compare the profile of the spectrum that you captured with a reference spectrum from the BASS2000 database: this is also how the software automatically determines what spectral line is observed, by comparing the profiles together.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With a 75mm length and an H-alpha profile, here&amp;#8217;s what we got:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/profile-75mm.jpg&quot; alt=&quot;profile 75mm&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can see that while the H-alpha profile is found, as soon as we move towards the wings, there are slight shifts between the local minimas.
When we switch to a 72mm length, these are perfectly aligned:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/shg700/profile-72mm.jpg&quot; alt=&quot;profile 72mm&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The SHG 700 is a fairly impressive instrument: it&amp;#8217;s robust, it&amp;#8217;s a pleasure to use with its microfocusers, and Minh is always super responsive and very patient.
Its use doesn&amp;#8217;t come without drawbacks, though.
It&amp;#8217;s weight, for example, restricts it to refractors which have a good focuser.
The dimension of the sun is also smaller than with the Sol&amp;#8217;Ex at equivalent focal length (see &lt;a href=&quot;https://solarchatforum.com/viewtopic.php?p=460891#p460891&quot;&gt;this post for an explanation&lt;/a&gt;).
However, it produces stunning images, sometimes rivalizing these produced with an etalon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While testing it, I faced this problem that the helium line images were significantly worse than with the Sol&amp;#8217;Ex, which didn&amp;#8217;t quite make sense.
After investigation, it turned out we had highlighted a difference in the specifications, a lens had been changed from 75mm to 72mm by the supplier, without letting MLAstro know.
That&amp;#8217;s a pity, but, in the end, the problem is very easy to fix in JSol&amp;#8217;Ex.
Be sure to upgrade to JSol&amp;#8217;Ex 2.11.2 which includes &lt;a href=&quot;https://github.com/melix/astro4j/pull/525&quot;&gt;a fix to update the focal length&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Automatic active region detection with JSol&amp;#8217;Ex 2.9</title>
      <link>https://melix.github.io/blog//2025/02-01-jsolex-actve-areas.html</link>
      <pubDate>Sat, 1 Feb 2025 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2025/02-01-jsolex-actve-areas.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The latest release of JSol&amp;#8217;Ex as of writing this blog post, JSol&amp;#8217;Ex 2.9, ships with a new ability: automatically detecting &lt;a href=&quot;https://en.wikipedia.org/wiki/Active_region&quot;&gt;active regions&lt;/a&gt;.
In this blog post, I will explain the principles and the algorithm I used, but also show its limits.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_about_active_regions&quot;&gt;About active regions&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, a bit of vocabulary.
An active region is a region of the Sun atmosphere where special activity occurs, such as flares or coronal mass ejections.
They don&amp;#8217;t have to be associated with sunspots, but in general, they are.
In JSol&amp;#8217;Ex, we&amp;#8217;re essentially detecting sunspots, and the terminology &quot;active regions&quot; essentially comes from the fact that we can use the &lt;a href=&quot;https://www.swpc.noaa.gov/&quot; class=&quot;bare&quot;&gt;https://www.swpc.noaa.gov/&lt;/a&gt;NOAA database] to label these active regions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_spectroheliographs&quot;&gt;Spectroheliographs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;An instrument like &lt;a href=&quot;http://www.astrosurf.com/solex/&quot;&gt;Christian Buil&amp;#8217;s Sol&amp;#8217;Ex&lt;/a&gt;, called a spectroheliograph (or SHG in short) doesn&amp;#8217;t offer any kind of &quot;live view&quot; like typical solar instruments like Coronado or Lunt instruments.
Instead, what we get is a video file, where each frames consists of a &quot;slice&quot; of the sun, observed as a portion of the light spectrum:&lt;/p&gt;
&lt;/div&gt;
&lt;video controls autoplay height=&quot;80&quot;&gt;
    &lt;source src=&quot;/blog/video/anim-spectrum.webm&quot;
            type=&quot;video/webm&quot;&gt;
&lt;/video&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The video above is an excerpt from a so-called &quot;scan&quot;: the principle is to have a slice of the sun passing through a slit, and a grating is used to spread the light into a spectrum.
Here, we are observing a curved dark line, which is the H-alpha line, and the &quot;wobbling&quot; we see around that line is an illustration of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Doppler_effect&quot;&gt;Doppler effect&lt;/a&gt;.
The idea of software like &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;Valérie Desnoux&amp;#8217;s INTI&lt;/a&gt; and &lt;a href=&quot;https://melix.github.io/astro4j/2.9.0/en/jsolex.html&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt; is to extract pixels from the studied line (here H-alpha) in order to reconstruct an image of the sun.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, as you can see in that animation, there&amp;#8217;s a lot more information available in each frame.
While we are mostly interested in the central line (here H-alpha), it&amp;#8217;s also interesting to look &quot;above&quot; or &quot;below&quot; the line, which is often referred to &quot;pixel shifting&quot;, in which case we&amp;#8217;re not studying H-alpha, but a different wavelength: that&amp;#8217;s one of the strenghts of Sol&amp;#8217;Ex, which makes it possible to do &quot;science&quot; at home!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, this video shows a couple interesting features:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;sometimes, you see some vertical dark lines appearing: these are features of the solar atmosphere. The darker lines which spread around multiple columns are these we are mostly interested in for this blog post: they correspond to sunspots!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;near the end of the video, on the right, you will see a white flash apparearing inside of of these regions: it&amp;#8217;s a solar flare!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This video is actually an excerpt from one of the many captures I&amp;#8217;ve done with Sol&amp;#8217;Ex, and I captured it during an eruption, on May 5th, 2024.
What you are seeing here is the &lt;a href=&quot;https://www.earth.com/news/sunspot-region-ar3664-blasted-earth-mars-may-2024-still-very-active/&quot;&gt;massive AR3664 region&lt;/a&gt; which was suject to multiple X-flares and resulted in beautiful auroras on Earth!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_automatic_active_region_detection&quot;&gt;Automatic active region detection&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;ve always considered that it would be a cool feature to be able to detect these lines automatically in JSol&amp;#8217;Ex, and provide an overlay of the detected sunspots.
Here we go, it is finally implemented in JSol&amp;#8217;Ex 2.9.0!
If you select the &quot;full processing mode&quot; or that you check the &quot;active regions&quot; checkbox in a custom process, then JSol&amp;#8217;Ex will automatically create an image of the sun with the detected active regions as an overlay:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-ar/ar-labels.jpg&quot; alt=&quot;ar labels&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Unfortunately that day I didn&amp;#8217;t capture a full disk, but you can see that JSol&amp;#8217;Ex annotated the disk with the detected active regions, but it also added the labels for these regions automatically.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s take another example with an image captured in Calcium K on January 17, 2025:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-ar/detection-calcium.jpg&quot; alt=&quot;detection calcium&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will notice 2 different colors for labels:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;blue labels are the ones detected by JSol&amp;#8217;Ex&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;red labels are the ones coming from the NOAA database, which were not detected&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sometimes, you will see like in the image above regions which are not detected, and others which are detected but not in the NOAA database.
The reason why not all of them are detected is that I had to choose &quot;reasonable&quot; detection thresholds, which work for most use cases.
I plan to improve the algorithm over time to make it more robust, based on your feedback.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_does_it_work&quot;&gt;How does it work?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The algorithm is based on a simple analysis of each frame.
If you open your SER file in JSol&amp;#8217;Ex video analyzer, you will see something similar to this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-ar/detection-debugger.jpg&quot; alt=&quot;detection debugger&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On the top, you see the original frame, with the curved H-alpha line.
On the bottom, you see the corrected frame, where the H-alpha line is straightened, and the active regions are highlighted in purple.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The algorithm is based on the following steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For each frame:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;Detect the borders of the sun&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For each column, compute the average intensity of the column, as well as its standard deviation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compute a 3rd order polynomial fit of the average intensity and standard deviation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;now, for each column, we compare its average intensity and standard deviation to the polynomial fits: if both of them are below a particular threshold, we consider that we have detected a candidate&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The reason to only keep candidates which have both average intensity and standard deviation below a threshold is because:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;sunspots characterize by a clear vertical line, which means that the standard deviation is low (most pixels have a similar value on the column)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sunspots are darker than the surrounding, which means that the average intensity is lower&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the moment, I&amp;#8217;m using the following thresholds (note that they may change in future releases, as I improve the accuracy):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;average intensity threshold: 0.95 times the predicted value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;standard deviation threshold: 0.85 times the predicted value&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once we have the results for all frames, we aggregate active regions by collecting adjacent candidates.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finally, we filter out regions which are too small, then perform clustering of regions which are close to each other.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The whole algorithm &lt;a href=&quot;https://github.com/melix/astro4j/blob/dbb2418318f4cb143726791830a32da00a35ae6f/jsolex-core/src/main/java/me/champeau/a4j/jsolex/processing/sun/detection/PhenomenaDetector.java#L40&quot;&gt;can be found here&lt;/a&gt; (note that it also includes redshift detection, which was discussed in a different blog post).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_limitations&quot;&gt;Limitations&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This algorithm proves to work relatively well in many different wavelengths (H-alpha, calcium, magnesium &amp;#8230;&amp;#8203;).
However, there are sometimes false positives.
This is for example the case when I&amp;#8217;m scanning in H-beta, due to the long focal length of my telescope and astigmatism, and the fact that H-beta provides a lot of details.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, the algorithm detects areas which are actually just noise:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that these are close to the north and south poles.
I have also noticed that the algorithm tends to detect noise as active regions when we&amp;#8217;re close to the limb, which is also why I&amp;#8217;m currently filtering these out.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-ar/active_regions_noise.jpg&quot; alt=&quot;active regions noise&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, I have chosen not to make the detection thresholds configurable, because I consider these internal implementation details, which may change in the future, and that I don&amp;#8217;t want to expose to the user.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_annotation_of_active_regions&quot;&gt;Annotation of active regions&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once piece of work that we didn&amp;#8217;t explain yet is how JSol&amp;#8217;Ex puts labels around active regions.
For this, we are using the &lt;a href=&quot;https://www.swpc.noaa.gov/products/solar-region-summary&quot;&gt;NOAA Solar Region Summary&lt;/a&gt; database.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This provides us, at a particular date, the list of active regions with their positions on the solar disk.
JSol&amp;#8217;Ex will compare these with the detected regions, and put the labels in different colors based on whether they were detected or not.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, the position of active regions will only be correct if:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;you have properly oriented your image (north at the top, east on the left): to help you with this, use the &quot;GONG&quot; tab on the right of the interface to download a reference image and compare with yours&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you are using an equatorial mount. If you are not, then make sure to check the new &quot;alt-az&quot; mode and enter your GPS coordinates in the settings, so that JSol&amp;#8217;Ex can compute the parallactic angle of the sun at the moment of the observation and automatically correct the orientation of the image.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The data from NOAA is cached in your local filesystem, so that we don&amp;#8217;t have to download it every time you open a video file.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_frequently_asked_questions&quot;&gt;Frequently Asked Questions&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Despite only having released this a day ago, I already have received the same question multiple times: can JSol&amp;#8217;Ex be used to annotate an &lt;em&gt;existing&lt;/em&gt; image of the sun, that is to say, take a JPG or PNG image and annotate it?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you have read carefully this blog post and that I explained things correctly, you will have understood that the answer is no: because my algorithm is based on the analysis of each frame, there&amp;#8217;s no such information available in a single image.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I hope you will enjoy this new feature in JSol&amp;#8217;Ex 2.9.0.
This blog post is a tentative explanation of the algorithm, and I will be happy to answer any questions you may have about it.
As always, feel free to contribute, JSol&amp;#8217;Ex is open source!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Extraction automatique d&amp;#8217;images Hélium avec JSol&amp;#8217;Ex</title>
      <link>https://melix.github.io/blog//2024/06-14-jsolex-helium-continuum.html</link>
      <pubDate>Fri, 14 Jun 2024 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2024/06-14-jsolex-helium-continuum.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans ce billet, je vais prendre exemple d&amp;#8217;un cas d&amp;#8217;utilisation particulier, l&amp;#8217;extraction d&amp;#8217;images Hélium, pour expliquer comment j&amp;#8217;envisage le développement de JSol&amp;#8217;Ex, dans l&amp;#8217;optique de simplifier, d&amp;#8217;une version à une autre, son exploitation par les utilisateurs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je rappelle à toutes fins utiles que le logiciel officiel n&amp;#8217;est pas JSol&amp;#8217;Ex mais bien &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI de Valérie Desnoux&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_principe_du_solex&quot;&gt;Principe du Sol&amp;#8217;Ex&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Rappelons tout d&amp;#8217;abord le principe de base du &lt;a href=&quot;http://www.astrosurf.com/solex/&quot;&gt;Sol&amp;#8217;Ex de Christian Buil&lt;/a&gt;.
Le concept requiert de reconstituer une image du soleil, ligne par ligne, en exploitant une vidéo dont chaque trame montre une partie du spectre solaire, centré sur une raie particulière que l&amp;#8217;on étudie.
La raie la plus communément étudiée est la raie H-alpha, qui, sur le spectre solaire, apparaît en absorption, c&amp;#8217;est à dire qu&amp;#8217;elle sera une ligne sombre sur une image du spectre :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-helium/spectre.jpg&quot; alt=&quot;spectre&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Figure 1. Image du spectre solaire, raie H-alpha sombre détectée&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;En haut, l&amp;#8217;image telle qu&amp;#8217;on la trouve dans la vidéo, la ligne est &quot;déformée&quot;. En bas, l&amp;#8217;image &quot;corrigée&quot;. Les points bleus correspondent à la détection de l&amp;#8217;effet Doppler, les lignes sombres verticales correspondent à des taches solaires.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les logiciels comme &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI&lt;/a&gt; et &lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt; exploitent le fait que la ligne étudiée est la plus sombre de l&amp;#8217;image pour se repérer.
Un des aspects fondamentaux de la reconstruction que je n&amp;#8217;avais honnêtement pas compris lorsque je me suis lancé dans ce projet, c&amp;#8217;est que &lt;strong&gt;tout le signal permettant de recomposer l&amp;#8217;image H-alpha se trouve dans cette ligne sombre&lt;/strong&gt;.
En effet, même si elle paraît &quot;noire&quot;, il y a en fait bien d&amp;#8217;infimes variations dans cette ligne, et c&amp;#8217;est celà qui nous sert à reconstituer une image !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock tip&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Tip&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;div class=&quot;title&quot;&gt;8 bits vs 16 bits&lt;/div&gt;
Cet aspect explique l&amp;#8217;importance d&amp;#8217;utiliser une acquisition en 16 bits et non en 8-bits.
En effet, si l&amp;#8217;acquisition est faite en 8 bits, on ne dispose que de 256 valeurs possibles pour encoder l&amp;#8217;ensemble de la dynamique de l&amp;#8217;image.
Si le signal ne se trouve qu&amp;#8217;au centre de la raie, on comprend vite qu&amp;#8217;on ne dispose alors que d&amp;#8217;un nombre très limité de valeurs pour ce qui se passe dans cette simple région.
En utilisant 16 bits, on augmente sensiblement notre capacité à encoder des valeurs de niveaux différents dans le centre de la raie, puisqu&amp;#8217;on dispose cette fois de 65536 valeurs possibles pour l&amp;#8217;ensemble de l&amp;#8217;image !
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_cas_des_raies_hélium&quot;&gt;Le cas des raies Hélium&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La détection de raies sombres permet, si la fenêtre de cropping du spectre est relativement petite, de se concentrer sur une raie à étudier.
Ca fonctionne très bien pour les raies H-alpha, Magnésium, Calcium K ou H, etc, qui sont des raies en absorption.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En revanche, la raie Hélium est une raie en émission : elle est &quot;claire&quot; au lieu d&amp;#8217;être sombre, mais elle est aussi impossible à distinguer dans la plupart des trames parce que noyée dans le flux.
Aussi les logiciels ne peuvent pas la trouver.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, comment fait JSol&amp;#8217;Ex, dans ses dernières versions, pour être capable de produire en 1 clic une image Hélium comme celle ci-dessous ?
La question est intéressante non seulement d&amp;#8217;un point de vue technique, mais aussi pour comprendre la façon dont j&amp;#8217;aborde le développement de JSol&amp;#8217;Ex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex-helium/image-helium.jpg&quot; alt=&quot;image helium&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le site de Christian Buil &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-observation.html&quot;&gt;est une nouvelle mine d&amp;#8217;information pour nous aider&lt;/a&gt; : pour pouvoir produire une telle image, il est nécessaire de prendre une raie sombre comme référence, puis d&amp;#8217;appliquer un &quot;décalage de pixels&quot; pour &quot;trouver&quot; la raie Hélium.
Enfin, il est nécessaire de procéder à une soustraction du continuum (une 2ème image).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette notion de décalage de pixels est bien connue des utilisateurs chevronnés du Sol&amp;#8217;Ex.
Le principe est relativement simple : au lieu de reconstituer une image en utilisant le centre de la raie détectée (la ligne rouge dans l&amp;#8217;image spectrale ci-dessus), on va reconstituer une image en se décalant vers le haut ou vers le bas de quelques pixels.
C&amp;#8217;est ce même principe qui permet de créer des images Doppler du soleil, qui montrent en bleu les régions qui s&amp;#8217;approchent de nous et en rouge celles qui s&amp;#8217;éloignent.
On peut même produire des timelapses assez spectaculaires comme cette animation que j&amp;#8217;ai réalisée le 5 juin 2024 et qui est générée par le logiciel en quelques minutes :&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;position:relative;padding-bottom:56.25%;height:0;overflow:hidden;&quot;&gt; &lt;iframe style=&quot;width:100%;height:100%;position:absolute;left:0px;top:0px;overflow:hidden&quot; frameborder=&quot;0&quot; type=&quot;text/html&quot; src=&quot;https://www.dailymotion.com/embed/video/x8znzg6?autoplay=1&quot; width=&quot;100%&quot; height=&quot;100%&quot; allowfullscreen title=&quot;Dailymotion Video Player&quot; allow=&quot;autoplay; web-share&quot;&gt; &lt;/iframe&gt; &lt;/div&gt;
&lt;br&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comme &lt;a href=&quot;https://www.youtube.com/watch?v=TuF6R9K5cqg&amp;amp;feature=youtu.be&quot;&gt;Christian l&amp;#8217;explique dans cette vidéo&lt;/a&gt;, trouver ce décalage de pixels n&amp;#8217;est pas forcément chose simple.
Tout d&amp;#8217;abord, il est nécessaire de trouver la raie &quot;sombre&quot; de référence : on utilisera traditionellement le doublet du sodium pour se répérer, puis on utilisera la raie Sodium D2 ou encore la raie Fe I présente à côté comme référence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ensuite, il faut trouver ce fameux décalage de pixels pour &quot;tomber&quot; sur la raie Hélium.
La vidéo de Christian ne montre pas les dernières améliorations que Valérie Desnoux a intégré à INTI pour rendre les choses plus simples, mais, grossièrement, il faut :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;faire une capture surexposée qui va nous permettre de &quot;voir&quot; la raie hélium&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;faire une capture &quot;normale&quot; pour disposer de l&amp;#8217;image à réellement traiter&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ouvrir INTI et traiter la première vidéo pour disposer de l&amp;#8217;image moyenne montrant la raie Hélium en bord de champ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;traiter la 2ème vidéo en mode &quot;raie libre&quot;, utiliser &quot;polynôme automatique&quot; et ouvrir l&amp;#8217;image moyenne calculée lors du premier traitement pour trouver le décalage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;enfin utiliser un autre logiciel comme i-Spec pour faire la soustraction&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette procédure, &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;bien que documentée&lt;/a&gt;, est très intimidante pour les utilisateurs et explique que peu se soient lancés dans ce défi.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans JSol&amp;#8217;Ex, la procédure est simplifiée au maximum :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;on fait une capture &quot;classique&quot;, intégrant la raie de référence (ex SoD2) et en utilisant un cropping assez large pour intégrer aussi la raie proche Hélium&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on ouvre le fichier dans JSol&amp;#8217;Ex : les images sont générées automatiquement, il n&amp;#8217;y a rien à calculer, pas de soustraction de continuum, rien, juste un clic !&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Ca ne prend que quelques secondes !&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;iframe width=&quot;1000&quot; height=&quot;600&quot; src=&quot;https://www.youtube.com/embed/yE6de4JM0Cw?si=O_qZrCAISZliPfxA&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_processus_de_simplification&quot;&gt;Le processus de simplification&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_imagemath&quot;&gt;ImageMath&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Avant d&amp;#8217;en arriver là, il a fallu de nombreuses améliorations, qui ont été livrées au fur et à mesure des versions.
La première, c&amp;#8217;est ce système de script que j&amp;#8217;ai appelé &quot;ImageMath&quot; (le nom est inspiré de PixelMath dans PixInsight) : il permet d&amp;#8217;utiliser des scripts pour produire des images que JSol&amp;#8217;Ex ne produit pas tout seul.
Cette avancée a permis d&amp;#8217;écrire un script qui produit une image Hélium à partir d&amp;#8217;un seul fichier SER :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Un exemple de script permettant de générer une image Hélium&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;[params]
# Entrer la valeur du décalage de raie
RaieHelium = -85
# Limites hautes et basses pour le continuum
ContinuumLo=-80
ContinuumHi=-70
# Stretch de l&apos;image
Stretch=10

## Variables temporaires
[tmp]
continuum = max(range(ContinuumLo,ContinuumHi))
helium_raw = autocrop(img(RaieHelium) - continuum)

## Maintenant les images !
[outputs]
helium = asinh_stretch(helium_raw, blackPoint, Stretch)
helium_fixed = asinh_stretch(fix_banding(helium_raw;BandWidth;BandIterations),blackPoint, Stretch)
helium_color = colorize(helium_fixed, &quot;Helium (D3)&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Néanmoins, vous noterez que ce script nécessite toujours de déterminer le décalage de la raie Hélium, ainsi que la position du continuum.
Ceci pouvait cependant être fait simplement avec le même fichier SER en l&amp;#8217;ouvrant dans le &quot;débogueur de raie&quot;, une procédure que &lt;a href=&quot;https://www.youtube.com/watch?v=EwUUg06opKU&quot;&gt;je décrivais à l&amp;#8217;époque dans une vidéo&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette procédure permettait ainsi d&amp;#8217;obtenir une image Hélium en moins de 5 minutes, ce qui était déja une amélioration sensible par rapport à avant : plus besoin de faire 2 vidéos distinctes et un décalage de pixels calculé par le logiciel avec l&amp;#8217;assistance de l&amp;#8217;utilisateur.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bien que ce soit une amélioration notable, on peut faire encore mieux.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_profils_spectraux&quot;&gt;Profils spectraux&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JSol&amp;#8217;Ex affiche depuis longtemps dans un onglet le &quot;profil spectral&quot; de l&amp;#8217;image étudiée et peut aussi calculer la &lt;em&gt;dispersion&lt;/em&gt;, mesurée en Angrstöms par pixel, d&amp;#8217;une image.
Ce profil correspond à l&amp;#8217;intensité des raies pour un décalage de pixels donné.
Depuis la version 2.3.0 cependant, j&amp;#8217;ai intégré une fonctionnalité qui permet de détecter automatiquement la raie étudiée grâce à la comparaison de ce profil à un profil de référence (les données sont issues de la &lt;a href=&quot;https://bass2000.obspm.fr/solar_spect.php&quot;&gt;base de données BASS2000&lt;/a&gt;).
Grâce à celà, il est désormais possible de savoir comment une image &quot;s&amp;#8217;aligne&quot; entre le profil de référence et celui qu&amp;#8217;on étudie.
Puisque l&amp;#8217;on connait à la fois la position de la raie de référence (Sodium D2 par exemple) et la dispersion, il est alors possible de calculer de combien de pixels on doit se déplacer pour trouver la raie Hélium !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette fonctionnalité est d&amp;#8217;ailleurs disponible dans les scripts sous le nom de &apos;find_shift`.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_soustraction_du_continuum&quot;&gt;Soustraction du continuum&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A ce stade, nous disposons donc d&amp;#8217;une image dont on sait qu&amp;#8217;elle contient une raie de référence (Sodium D2 ou Fer Fe I) mais aussi le décalage en pixels de la raie Hélium.
Il nous manque cependant la soustraction du continuum.
Là encore, le script ci-dessus montre qu&amp;#8217;il fallait entrer une valeur &quot;à la main&quot; pour trouver ce qu&amp;#8217;il fallait soustraire.
Une façon simple de procéder était encore une fois d&amp;#8217;ouvrir le débogueur et de regarder les lignes plus claires dans le spectre : l&amp;#8217;oeil étant assez sensible aux changements de contraste, il n&amp;#8217;était pas trop compliqué de trouver un intervalle raisonnable pour le continuum.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Néanmoins, si on souhaite arriver à un traitement complètement automatique, on ne peut plus se baser sur une valeur &quot;pifométrique&quot;.
Une façon naïve de régler le problème aurait été d&amp;#8217;utiliser un décalage fixe (par exemple 15 pixels).
Cependant, ça ne fonctionne pas, pour plusieurs raisons :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;le décalage dépend de la résolution (taille des pixels, dispersion)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on peut tomber sur une raie trop sombre, cette région du spectre étant assez contrastée&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le résultat est très sensible à l&amp;#8217;exposition&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour cette raison, j&amp;#8217;ai ajouté une fonctionnalité qui calcule un &quot;continuum synthétique&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il faut noter que contrairement à l&amp;#8217;image &quot;continuum&quot; qui utilise un décalage fixe (et configurable) dans les traitements standards, ce continuum synthétique est utilisé uniquement dans le contexte du traitement Hélium, ou lors de l&amp;#8217;utilisation de la fonction &lt;code&gt;continuum()&lt;/code&gt; dans un script.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;idée de cette fonction est de calculer une image qui représente au mieux le continuum à soustraire.
Au lieu d&amp;#8217;utiliser un seul décalage de pixels, on va effectuer un calcul à partir de plusieurs décalages (cette fonction nécessite donc plus de ressources lors du traitement).
Ainsi la première chose à comprendre c&amp;#8217;est qu&amp;#8217;il ne s&amp;#8217;agira pas d&amp;#8217;une image à une longueur d&amp;#8217;onde précise, mais bel et bien d&amp;#8217;une image synthétique basée sur des propriétés statistiques.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En premier lieu, on effectue un échantillonnage des images à différents décalages de pixels, du minimum possible au maximum possible par rapport à la fenêtre de cropping du spectre et de la distorsion.
Par exemple, si chaque trame fait 2000x200 pixels, on dispose potentiellement de 100 décalages entiers (la hauteur de l&amp;#8217;image).
Cependant, à cause de la distorsion, seuls un sous-ensemble nous permet d&amp;#8217;avoir des lignes complètes lors de la reconstruction (disons, 180 lignes, qui donneront 180 images).
Sur ces 180 décalages possible, nous n&amp;#8217;allons, pour des raisons de performance, uniquement en retenir un échantillon (environ 1/3), ce qui nous donnera donc 60 images à étudier.
Sur ces 60 images, on élimine celles qui correspondent à un décalage de pixel trop proche de la raie de référence puisque de manière évidente elles ne correspondent pas au continuum.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dès lors commence l&amp;#8217;analyse statistique : pour chacune de ces images, on calcule leur valeur moyenne.
Ensuite, nous calculons la moyenne de ces moyennes et nous ne conservons que les images dont la moyenne est supérieure à cette moyenne.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A ce stade, il nous reste donc quelques candidates, dont la luminosité est suffisante pour être considérée comme le continuum, mais on dispose bien d&amp;#8217;une liste d&amp;#8217;images.
La dernière étape consiste donc à calculer la médiane de toutes ces images, pour obtenir un et un seul &quot;continuum synthétique&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si on reprend les étapes, celà nous donne par exemple:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;on dispose de 60 images à des décalages de pixels (entiers)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on retire les 8 qui sont au centre de la raie étudiée, il en reste 52&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on calcule la valeur moyenne de chacune de ces images : 5000, 8000, 5200, 6400, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on calcule la moyenne de toutes ces moyennes, par ex: 6000&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on ne retient que les images dont la moyenne est supérieure à cette moyenne, disons qu&amp;#8217;il en reste 30&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on calcule la médiane de ces 30 images&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il ne nous reste donc plus qu&amp;#8217;à faire la soustraction entre l&amp;#8217;image au décalage de pixels de la raie Hélium avec le continuum synthétique calculé et on obtient l&amp;#8217;image Hélium ci-dessus, en quelques secondes seulement !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans ce billet, j&amp;#8217;ai décris la façon dont je procède pour améliorer JSol&amp;#8217;Ex.
En premier lieu, il s&amp;#8217;agit d&amp;#8217;identifier un besoin particulier, par exemple, ici, produire une image Hélium.
A partir de ce besoin, il s&amp;#8217;agit de chercher comment simplifier un tel traitement.
La simplification ne se fait alors qu&amp;#8217;à partir de ce dont je dispose à un instant &lt;em&gt;t&lt;/em&gt;.
Par exemple, dans un premier temps, il a s&amp;#8217;agit d&amp;#8217;ajouter un système de scripts, qui, outre le traitement des images Hélium, permet d&amp;#8217;exploiter la richesse des données disponibles dans un scan.
Les personnes intéressées peuvent en apprendre plus sur les scripts &lt;a href=&quot;https://youtu.be/8XKzFcmvqfI&quot;&gt;dans ce tutoriel&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ensuite, il a s&amp;#8217;agit d&amp;#8217;ajouter des fonctionnalités permettant de simplifier la configuration pour les utilisateurs, en l&amp;#8217;occurrence la détection automatique de raie, puis d&amp;#8217;exploiter ces nouvelles fonctionnalités pour simplifier encore plus le traitement des images.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, il s&amp;#8217;agit d&amp;#8217;une méthode très itérative, mais toujours dans le but de livrer des incréments fournissant une certaine valeur ajoutée aux utilisateurs.
La bonne nouvelle, c&amp;#8217;est que j&amp;#8217;ai beaucoup d&amp;#8217;autres idées en tête !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_ressources&quot;&gt;Ressources&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt; (téléchargement et documentation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI&lt;/a&gt; (logiciel officiel)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-traitement.html&quot;&gt;Sol&amp;#8217;Ex&lt;/a&gt; (site officiel Sol&amp;#8217;Ex)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JSol&amp;#8217;Ex 2.2.0 et amélioration du contraste</title>
      <link>https://melix.github.io/blog//2024/04-25-jsolex-contrast.html</link>
      <pubDate>Thu, 25 Apr 2024 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2024/04-25-jsolex-contrast.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/melix/astro4j/releases/tag/2.2.0&quot;&gt;JSol&amp;#8217;Ex 2.2.0&lt;/a&gt; est tout juste sorti ! Dans cette version, j&amp;#8217;ai particulièrement travaillé sur l&amp;#8217;amélioration des contrastes. En effet, celles et ceux qui m&amp;#8217;ont entendu parler de ce logiciel savent que je râle depuis longtemps sur mon algo d&amp;#8217;amélioration de contraste. Dans JSol&amp;#8217;Ex, il y a plusieurs algorithmes d&amp;#8217;implémentés. Historiquement, le premier était une transformation sinus hyperbolique inverse, qui fonctionne relativement bien pour faire ressortir les zones plus sombres, mais éclaircit trop le reste. L&amp;#8217;autre algorithme, utilisé aussi par &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI&lt;/a&gt;, c&amp;#8217;est la normalisation locale d&amp;#8217;histogramme (CLAHE).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_les_problèmes_avec_clahe&quot;&gt;Les problèmes avec CLAHE&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;CLAHE est un algorithme qui améliore sensiblement le contraste. Cependant, je n&amp;#8217;ai jamais été très content du résultat. Je ne sais pas comment Valérie Desnoux fait dans INTI, qui a l&amp;#8217;air de s&amp;#8217;en sortir mieux, mais dans JSol&amp;#8217;Ex les résultats obtenus sont assez moyens.
En particulier, je note plusieurs défauts :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;la création d&amp;#8217;artéfacts, liés au fait que cet algorithme travaille sur des &quot;tuiles&quot; d&amp;#8217;une taille donnée. Plus la taille de la tuile est élevée, moins l&amp;#8217;amélioration de contraste est aggressive, mais plus les artéfacts sont visibles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sur l&amp;#8217;image du soleil, les limbes sont toujours éclaircis, ce qui me mène au point suivant&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;les images solaires paraissent plus &quot;plates&quot; : le relief, en particulier l&amp;#8217;obscurcissement lié à la sphéricité du soleil, disparaît. C&amp;#8217;est aussi un effet mécanique de l&amp;#8217;algorithme lui-même : plus la taille des tuiles est faible, moins on peut utiliser de valeurs distinctes. Ainsi pour une taille de tuile à 16 pixels, on aura au maximum 256 valeurs possibles (pour une image 16 bits avec 65536 valeurs à l&amp;#8217;origine). Or, les meilleurs résultats, sur Sol&amp;#8217;Ex, sont obtenus avec une taille de tuile de 8 pixels, soit une réduction à 64 valeurs possibles maximum.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;il y a trop de paramètres possibles : la taille des tuiles, la dynamique et enfin le &quot;facteur de coupe&quot; pour l&amp;#8217;égalisation. Sans entrer dans les détails, trouver une combinaison qui fonctionne bien indépendamment de la taille des images en entrée, de la dynamique de l&amp;#8217;image et enfin du type d&amp;#8217;image (H-alpha, calcium) est presque impossible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour illustrer mon propos, voici par exemple un disque solaire (le fichier SER est &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-traitement.html&quot;&gt;celui disponible sur le site de Christian Buil&lt;/a&gt;) traité par JSol&amp;#8217;Ex 2.1 (version précédente donc), avec les paramètres par défaut, une tuile de taille 16 pixels (à gauche) ou 64 pixels (à droite) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;
&lt;div class=&quot;container-fluid&quot;&gt;
&lt;div class=&quot;row&quot;&gt;
   &lt;div class=&quot;col-md-6&quot;&gt;
      &lt;img class=&quot;img-responsive pop&quot; src=&quot;/blog/img/jsolex2_2/clahe_16_jsolex_2.1.jpg&quot;&gt;
   &lt;/div&gt;
   &lt;div class=&quot;col-md-6&quot;&gt;
      &lt;img class=&quot;img-responsive pop&quot; src=&quot;/blog/img/jsolex2_2/clahe_64_jsolex_2.1.jpg&quot;&gt;
   &lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On note déja clairement éclaircissement des limbes, et des artéfacts &quot;carrés&quot; qui apparaissent dès que la taille des tuiles augmente.
Trouver les bons paramètres qui conviennent à tous étant compliqué, JSol&amp;#8217;Ex offrait déja la possibilité de changer ces paramètres (taille de tuile, intensité, &amp;#8230;&amp;#8203;) mais je pense que peu d&amp;#8217;utilisateurs le faisaient.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Aussi ais-je décidé d&amp;#8217;ajouter un algorithme dans JSol&amp;#8217;Ex 2.2 dédié aux images solaires.
Pour vous donner un peu envie de lire la suite, voici ce qu&amp;#8217;on peut obtenir avec JSol&amp;#8217;Ex 2.2 sur la même image :&lt;/p&gt;
&lt;/div&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/christian-jsolex-2.2-decon.jpg&quot; class=&quot;img-responsive center-block&quot; width=&quot;50%&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_nouvel_algorithme&quot;&gt;Nouvel algorithme&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le nouvel algorithme est disponible dans JSol&amp;#8217;Ex 2.2 et est l&amp;#8217;algorithme utilisé par défaut.
Il combine plusieurs techniques, dont une correction du gamma avec masques, CLAHE et un stretching dynamique de l&amp;#8217;image, pour produire une image plus digne de ce que Sol&amp;#8217;Ex peut faire.
Je ne prétends pas que cet algorithme est parfait, il a lui aussi des défauts, mais il semble être un bon compromis.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Afin de vérifier mes assertions, j&amp;#8217;ai procédé méthodiquement à une comparaison des images produites avec les paramètres par défaut de INTI, JSol&amp;#8217;Ex 2.1 et JSol&amp;#8217;Ex 2.2 (la seule modification est l&amp;#8217;autocrop activé et un retournement vertical pour que les images soient orientées de la même façon).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Commençons par la vidéo H-alpha de démonstration utilisée par Christian Buil sur son site.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Les images pouvant être difficiles à comparer en taille réduite, je vous invite à faire un clic doit et ouvrir l&amp;#8217;image dans un nouvel onglet pour comparer.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-1.jpg&quot; alt=&quot;comparaison panel 1&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On note clairement que sur JSol&amp;#8217;Ex 2.1, il y avait certes une amélioration de contraste, mais elle se faisait au prix d&amp;#8217;artéfacts et d&amp;#8217;une perte de relief.
En revanche, JSol&amp;#8217;Ex 2.2 offre une image plus nette que celle d&amp;#8217;INTI, sans avoir les défauts de CLAHE.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Continuons avec une autre image solaire en H-alpha, avec plus de dynamique :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-2.jpg&quot; alt=&quot;comparaison panel 2&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Là encore on remarque que JSol&amp;#8217;Ex 2.1 produisait une image raisonnable mais assez saturée et surtout &quot;plate&quot;.
La version 2.2.0, quant à elle, offre une meilleure dynamique tout en préservant les détails et cette impression de profondeur.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous pouvons aussi comparer les résultats sur une image obtenue avec une plus longue focale et un disque partiel :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-3.jpg&quot; alt=&quot;comparaison panel 3&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette fois-ci on note que les 3 logiciels s&amp;#8217;en tirent honorablement.
Cependant, JSol&amp;#8217;Ex 2.1.3 affiche une image moins contrastée que la v2.2.0, alors qu&amp;#8217;INTI v6 affiche une image légèrement plus floue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Malheureusement suite à une fausse manipulation, j&amp;#8217;ai perdu la plupart de mes fichiers SER en raie calcium. J&amp;#8217;ai cependant pu faire des comparaisons, sur des fichiers loins d&amp;#8217;être idéaux.
Les résultats sont cependant intéressants :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-4.jpg&quot; alt=&quot;comparaison panel 4&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette fois-ci, on constate que JSol&amp;#8217;Ex 2.1 s&amp;#8217;en sortait plutôt bien. INTI là encore fait un travail remarquable, mais JSol&amp;#8217;Ex 2.2 sature trop l&amp;#8217;image.
C&amp;#8217;est un défaut que j&amp;#8217;espère arriver à corriger, qui est lié au fait que les images calcium on un histogramme avec une gaussienne à base très large.
Il est néanmoins possible d&amp;#8217;atténuer la saturation en choisissant un facteur de correction moins fort (par exemple 1.1 au lieu de la valeur par défaut 1.5), ce que je vous encourage à faire pour les images Calcium (conserver le 1.5 pour le h-alpha, baisser pour le calcium) :&lt;/p&gt;
&lt;/div&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/calcium-1-jsolex-2-2-facteur-1.1.jpg&quot; class=&quot;img-responsive center-block&quot; width=&quot;50%&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le résultat dépendra cependant beaucoup de l&amp;#8217;exposition initiale de votre vidéo. Voici un autre exemple en raie calcium K:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-5.jpg&quot; alt=&quot;comparaison panel 5&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il est utile de noter que si vous n&amp;#8217;êtes pas satisfait du nouvel algorithme, il est tout à fait possible de repasser à CLAHE :&lt;/p&gt;
&lt;/div&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/config-params.jpg&quot; class=&quot;img-responsive center-block&quot; width=&quot;50%&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, il vous est tout à fait possible d&amp;#8217;être plus ou moins &quot;aggressif&quot; sur l&amp;#8217;amélioration de constraste à effectuer.
Ansi, dans les paramètres de traitement, vous pouvez changer le facteur &lt;em&gt;gamma&lt;/em&gt; qui permet d&amp;#8217;assombrir l&amp;#8217;image.
Pour l&amp;#8217;exemple, si on pousse les curseurs un peu loin (par exemple à &lt;em&gt;4&lt;/em&gt; dans l&amp;#8217;image suivante), vous constaterez que l&amp;#8217;image reste exploitable, et surtout que les défauts de CLAHE qui a tendance à aplatir les images est complètement disparu :&lt;/p&gt;
&lt;/div&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/gamma-4.jpg&quot; class=&quot;img-responsive center-block&quot; width=&quot;50%&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_pour_aller_encore_plus_loin&quot;&gt;Pour aller encore plus loin&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Tout d&amp;#8217;abord, JSol&amp;#8217;Ex offre un &lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html#imagemath&quot;&gt;langage de script&lt;/a&gt; qui permet d&amp;#8217;aller bien plus loin dans les traitements, de générer automatiquement des animations, etc.
Bien sûr, les améliorations de JSol&amp;#8217;Ex 2.2 sont disponibles dans les scripts par l&amp;#8217;intermédiaire de 2 nouvelles fonctions : &lt;code&gt;adjust_gamma&lt;/code&gt; qui permet de réaliser une simple correction de gamma sur l&amp;#8217;image, et &lt;code&gt;auto_constrast&lt;/code&gt; qui correspond à la correction décrite dans ce billet de blog.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, nous n&amp;#8217;avons pas encore parlé des fonctionnalités désactivées par défaut, mais qui étaient déja disponibles dans JSol&amp;#8217;Ex : la déconvolution et l&amp;#8217;amélioration de la netteté.
Ces deux options sont activables dans les paramètres de traitement :&lt;/p&gt;
&lt;/div&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/config-params-2.jpg&quot; class=&quot;img-responsive center-block&quot; width=&quot;50%&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je ne recommande pas nécessairement de cocher la case &quot;aiguiser les détails&quot; si vous avez des images trop bruitées.
Cette dernière ligne compare donc la même image, traitée avec &lt;a href=&quot;/blog/img/jsolex2_2/halpha-3-inti-6.png&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;INTI v6&lt;/a&gt;, JSol&amp;#8217;Ex 2.2 (dernière version donc), mais &lt;a href=&quot;/blog/img/jsolex2_2/halpha-3-jsolex-2.2.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;sans déconvolution&lt;/a&gt;, &lt;a href=&quot;/blog/img/jsolex2_2/halpha-3-jsolex-2.2-decon.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;avec déconvolution&lt;/a&gt; et finalement &lt;a href=&quot;/blog/img/jsolex2_2/halpha-3-jsolex-2.2-decon-sharpen.jpg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;avec déconvolution et amélioration des détails&lt;/a&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/comparaison-panel-6.jpg&quot; alt=&quot;comparaison panel 6&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En ce qui me concerne, je trouve la version déconvoluée particulièrement plaisante à l&amp;#8217;oeil, et j&amp;#8217;active donc systématiquement la déconvolution :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2_2/halpha-3-jsolex-2.2-decon.jpg&quot; alt=&quot;halpha 3 jsolex 2.2 decon&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En conclusion, dans ce billet je vous ai présenté le nouvel algorithme de correction de contraste, activé par défaut dans JSol&amp;#8217;Ex 2.2.
Je pense que les résultats sont assez probants, et que JSol&amp;#8217;Ex n&amp;#8217;a plus à rougir de INTI en ce qui concerne les images avec amélioration de contraste.
Cependant, je rappelle encore une fois que le logiciel officiel &lt;strong&gt;est&lt;/strong&gt; INTI, que c&amp;#8217;est le seul validé avec le sérieux de Christian Buil et Valérie Desnoux.
Si vous voulez déposer des images sur BASS2000, vous &lt;strong&gt;devez&lt;/strong&gt; utiliser INTI.
Par ailleurs, je vous conseille toujours de comparer les résultats, ne considérez pas que JSol&amp;#8217;Ex fait un meilleur travail, c&amp;#8217;est probablement faux.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Par exemple, il reste des améliorations à faire sur les images calcium. Mais il est cependant tout à fait possible de modifier les paramètres par défaut, voire de changer d&amp;#8217;algorithme.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;N&amp;#8217;oubliez pas non plus que JSo&amp;#8217;Ex offre d&amp;#8217;autres fonctionnalités comme la colorisation automatique des images, le stacking, la création de mosaïques solaires ou encore un langage de script particulièrement puissant, qui vous permet par exemple de générer des animations automatiquement.
Je vais donc conclure ce billet avec un exemple de script qui utilise cette nouvelle amélioration de contraste pour produire une animation qui nous fait plonger dans l&amp;#8217;atmosphère solaire en jouant sur le décalage de pixels :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;# Décalage de pixels qu&apos;on applique, de -15 à +15, pas de 0.5
images=range(-15,15,.5)
# On calcule une image corrigée de ses transversalliums
corrigee=fix_banding(images,32,40)
# Déconvolution
decon=rl_decon(corrigee)
# On redimensionne
redim=rescale_rel(autocrop2(decon,1.1),.5,.5)
# On applique la correction de contraste décrite dans ce billet
cst=auto_contrast(redim,1.5)

[outputs]
# Enfin on produit l&apos;animation (75ms entre chaque frame)
animation=anim(cst,75)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;text-center&quot;&gt;
 &lt;video width=&quot;640&quot; height=&quot;640&quot; controls&gt;
  &lt;source src=&quot;https://melix.github.io/blog/img/jsolex2_2/animation.webm&quot; type=&quot;video/webm&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_bonus&quot;&gt;Bonus&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;en profite enfin pour partager deux vidéos, à destination des débutants sur Sol&amp;#8217;Ex, que j&amp;#8217;ai faites récemment :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=NsDgg4o2SDw&quot;&gt;Trouver le soleil sans chercheur solaire&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=8lWXcPG16I0&quot;&gt;Régler exposition, gain et binning&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_ressources&quot;&gt;Ressources&lt;/h3&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/melix/astro4j&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt; (téléchargement)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://melix.github.io/astro4j/latest/fr/jsolex.html&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt; (documentation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI&lt;/a&gt; (logiciel officiel)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-traitement.html&quot;&gt;Sol&amp;#8217;Ex&lt;/a&gt; (site officiel Sol&amp;#8217;Ex)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Adaptive_histogram_equalization&quot;&gt;CLAHE&lt;/a&gt; (algorithme)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Gamma_correction&quot;&gt;Gamma correction&lt;/a&gt; (algorithme)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Vers un effondrement civilisationnel ?</title>
      <link>https://melix.github.io/blog//2024/02-22-effondrement.html</link>
      <pubDate>Thu, 22 Feb 2024 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2024/02-22-effondrement.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Coucher des mots sur le papier, aussi numérique soit-il, est une forme de thérapie : faire sortir ce qui doit sortir, organiser ses idées, prendre le temps de la réflexion, se rassurer parfois.
Prédire le futur est bien évidemment impossible, mais il y a des ressentis, des signaux plus ou moins faibles, qui peuvent nous donner une idée de ce qui nous attend.
Ce billet n&amp;#8217;a aucune prétention scientifique, il s&amp;#8217;agit plutôt d&amp;#8217;une synthèse des nombreuses sources que j&amp;#8217;ai lues ou visionnées sur le sujet au cours des dernières années.
Au centre de ce texte, une interrogation : est-on en train d&amp;#8217;assister à la fin de notre civilisation ?
Après tout, l&amp;#8217;Histoire est faite de disparitions de civilisations, pourquoi la nôtre survivrait plus qu&amp;#8217;une autre ?
En trame de fond, la question qui me préoccupe le plus : a-t-on déjà scellé le sort de nos enfants ?
A qui s&amp;#8217;adresse ce billet ?
A ma famille et mes amis, probablement.
À mes enfants, sûrement, pour exprimer mes regrets, mes craintes, mais aussi mon espoir envers eux.
Enfin à tous celles et ceux qui devraient le lire mais qui ne le feront jamais, certainement.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_genèse&quot;&gt;La genèse&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai une sensibilité à la fois sur les sujets écologiques et scientifiques depuis ma jeunesse.
Je me souviens encore des conversations avec mon copain Erwan, au collège.
Nous arrivions tôt le matin, bien avant le début des cours, et avions entre autres de longues conversations sur la Terre et comment la sauver.
A l&amp;#8217;époque, nous ne parlions pas de réchauffement climatique : les sujets tournaient essentiellement autour de la pollution, du trou dans la couche d&amp;#8217;ozone, de la disparition des papillons de nuit ou des ours polaires.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans ce terreau fertile aux idées dites écologistes, j&amp;#8217;étais biberonné aux séries SF, et en particulier par Star Trek, série humaniste qui m&amp;#8217;a profondément marqué.
Il en est ressorti une double culture, à la fois la prise en compte de la sauvegarde de l&amp;#8217;environnement, mais aussi un profond respect pour la science et ce qu&amp;#8217;elle permet d&amp;#8217;expliquer du monde.
J&amp;#8217;aime la rigueur de la démarche scientifique, ainsi que la capacité à se remettre en question, en opposition aux points de vue dogmatiques que l&amp;#8217;on trouve par exemple dans les religions.
Agnostique, j&amp;#8217;ai cherché mes réponses dans la science et continue de le faire aujourd&amp;#8217;hui, notamment en appliquant le principe du &lt;a href=&quot;https://fr.wikipedia.org/wiki/Rasoir_d%27Ockham&quot;&gt;rasoir d&amp;#8217;Okham&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;avais déja sur ce blog abordé le sujet &lt;a href=&quot;https://melix.github.io/blog/2022/07/je-suis-le-gars-chiant.html&quot;&gt;du rationnel et des reproches qu&amp;#8217;on m&amp;#8217;en a fait&lt;/a&gt;.
Cette rationalité est aussi celle qui me pousse à écrire et partager mon angoisse : lorsqu&amp;#8217;on a un &quot;esprit scientifique&quot; et que l&amp;#8217;on a les informations dont on dispose aujourd&amp;#8217;hui, il est difficile, voire impossible d&amp;#8217;être optimiste.
Pire, il est difficile d&amp;#8217;imaginer autre chose qu&amp;#8217;un effondrement pur et simple de notre société.
Cette prise de conscience, ce pessimisme, doit se convertir en énergie, en action.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Précisons cependant que lorsque je parle d&amp;#8217;effondrement civilisationnel, je me moque éperdument des fantasmes de l&amp;#8217;extrême-droite sur le grand remplacement (culturel), de leur racisme, de leur xénophobie : je suis à l&amp;#8217;opposé de tout cela, pour moi la &quot;tradition chrétienne de la France&quot; n&amp;#8217;est qu&amp;#8217;une vaste blague à l&amp;#8217;échelle de l&amp;#8217;Humanité et je suis de ceux qui pensent que l&amp;#8217;égalité des droits n&amp;#8217;est pas négociable, quelle que soit son origine, son orientation sexuelle ou politique.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Non, je parle ici d&amp;#8217;un effondrement de notre mode de vie basé sur la consommation, la propriété privée et la mondialisation : je parle de la disparition possible de la démocratie et du retour de la guerre et des horreurs qui vont avec.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_de_quoi_parle_t_on&quot;&gt;De quoi parle-t-on ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une fois que vous &lt;em&gt;savez&lt;/em&gt; ce qui se passe au niveau climatique, il n&amp;#8217;y a que trois options possibles : le renoncement, le cynisme ou l&amp;#8217;action.
Pour mes enfants, j&amp;#8217;ai choisi d&amp;#8217;agir : c&amp;#8217;est notamment pour cela que je me suis lancé en politique, certes à un niveau local puisque limité aux municipales, il y a quelques années.
C&amp;#8217;est aussi pour celà que je communique beaucoup sur les sujets écologique et politique, quitte à en agacer quelques uns.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une des premières choses dont il faut prendre conscience, c&amp;#8217;est l&amp;#8217;urgence climatique.
Je discute souvent du réchauffement avec des personnes sensibilisées au sujet, mais paradoxalement, rares sont ceux qui ont vraiment conscience de l&amp;#8217;urgence de la situation.
Au contraire, on entend dire que les écolos sont pénibles, le RN va même jusqu&amp;#8217;à affirmer que &lt;a href=&quot;https://www.lepoint.fr/politique/climat-le-depute-rn-thomas-menage-accuse-le-giec-d-exagerer-21-08-2023-2532248_20.php&quot;&gt;le GIEC exagère&lt;/a&gt;.
Rappelons que le GIEC est un organe international qui synthétise les conclusions de centaines d&amp;#8217;études et que de part la nature extrêmement politique de ses rapports, c&amp;#8217;est précisément plutôt l&amp;#8217;inverse qui se produit, avec des rapports qui proposent différents scénarios, les politiques préférant regarder les plus optimistes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Récemment, Jean-Marc Jancovici, spécialiste mondial du sujet, inventeur du concept de &quot;bilan carbone&quot; était &lt;a href=&quot;https://www.youtube.com/watch?t=1497&amp;amp;v=G3-L9UtBP78&amp;amp;feature=youtu.be&quot;&gt;auditionné au Sénat&lt;/a&gt; devant des élus parfois médusés par ses réponses.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
1.5 degrés, c&amp;#8217;est mort. 2 degrés, sauf chute de comète ou effondrement économique, c&amp;#8217;est parti pour être mort.
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; Jean-Marc Jancovici&lt;br&gt;
&lt;cite&gt;Audition au Sénat du 12 Février 2024&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pourtant, aucune des affirmations de Jancovici, dont je me sens proche idéologiquement au moins sur ces sujets, ne devraient être surprenantes : on le sait depuis longtemps, les rapports s&amp;#8217;enchaînent, mais l&amp;#8217;inaction persiste.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une grosse partie du problème est qu&amp;#8217;il est difficile pour un être humain, de quantifier par nos simples sens une augmentation de 2 degrés.
Aujourd&amp;#8217;hui encore, une canicule est systématiquement illustrée par des vacanciers à la plage, là où on devrait montrer des ruisseaux asséchés, des forêts qui partent en fumée, des personnes âgées en détresse, des agriculteurs qui ne peuvent plus arroser leurs cultures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il est important de comprendre que 2 degrés, c&amp;#8217;est une moyenne mondiale : le réchauffement est plus important dans certaines zones de la planète (les pôles par exemple) et moins dans d&amp;#8217;autres.
Une différence de 2 degrés à l&amp;#8217;échelle planétaire, c&amp;#8217;est 3 ou 4 degrés en plus en France (en 2022, nous avons atteint &lt;a href=&quot;https://www.ecologie.gouv.fr/impacts-du-changement-climatique-atmosphere-temperatures-et-precipitations&quot;&gt;+2.7⁰&lt;/a&gt;)
Entre -1.8 et -18 degrés, c&amp;#8217;est précisément &lt;a href=&quot;https://wp.unil.ch/geoblog/2022/07/quel-temps-faisait-il-il-y-a-20-000-ans/&quot;&gt;ce qui séparait l&amp;#8217;ère glacière de l&amp;#8217;ère pré-industrielle&lt;/a&gt;.
A l&amp;#8217;époque, nous avions des glaciers de plusieurs centaines de mètres de haut, l&amp;#8217;Angleterre était reliée au continent (les océans étaient 120 mètres plus bas).
Si une si petite différence de température pouvait provoquer une telle conséquence, imaginez ce que 2 ou 3 degrés en plus pourraient donner.
Précisément, on a du mal à s&amp;#8217;imaginer, et c&amp;#8217;est pour celà que le GIEC établit des scénarios, des prédictions.
Ainsi, il est plutôt rassurant que &lt;a href=&quot;https://bonpote.com/pourquoi-le-gouvernement-a-raison-de-preparer-la-france-a-4-degres/&quot;&gt;la France se prépare à un scénario à +4⁰&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pourtant, lorsque la France est touchée par une &quot;&lt;a href=&quot;https://www.tf1info.fr/meteo/meteo-baisse-des-temperatures-en-france-peut-on-reellement-parler-de-vague-de-froid-2281908.html&quot;&gt;vague de froid&lt;/a&gt;&quot; (je le mets entre guillemets parce que ces vagues sont moins fréquentes et moins fortes qu&amp;#8217;il y a 20 ans), nous retrouvons ces réflexes climatosceptiques, en confondant météo (temps court) et climat (temps long).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Aujourd&amp;#8217;hui nous sommes, mondialement, au niveau de la barre des 1.5 degrés et les conséquences au niveau local se font déja sentir :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;en Espagne, des sécheresses à répétition ont annihilé les capacités agricoles du pays. Le &lt;a href=&quot;https://www.liberation.fr/environnement/agriculture/canicule-et-agriculture-lespagne-ne-pourra-plus-etre-le-verger-de-leurope-20230721_EY7ECPTN5JBE3IQRHQFJXMXOWQ/?utm_medium=Social&amp;amp;utm_source=Facebook&amp;amp;xtor=CS7-50-#Echobox=1689965095&quot;&gt;verger de l&amp;#8217;Europe&lt;/a&gt; va disparaître. Le sud de la France commence à souffrir des mêmes déréglements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;en Catalogne, cette même sécheresse &lt;a href=&quot;https://www.courrierinternational.com/article/espagne-secheresse-la-catalogne-va-declarer-l-etat-d-urgence&quot;&gt;menace l&amp;#8217;approvisionnement en eau potable de millions d&amp;#8217;habitants&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;en France, des événements climatiques de plus en plus extrêmes &lt;a href=&quot;https://www.letemps.ch/monde/europe/les-inondations-a-repetition-mettent-le-nord-de-la-france-face-a-des-questionnements-vertigineux&quot;&gt;menacent populations et industries&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A 1.5 degrés, nous avons déja scellé le destin de pays entiers.
Les îles Tuvalu, par exemple, vont disparaître.
Ce pays est le premier du monde à avoir signé un &lt;a href=&quot;https://www.geo.fr/environnement/australie-offre-asile-climatique-aux-citoyens-de-tuvalu-deplaces-par-la-montee-des-eaux-217488&quot;&gt;accord d&amp;#8217;asile climatique avec l&amp;#8217;Australie&lt;/a&gt;.
Imaginez-vous votre pays entier disparaître ?
Ceci nous semble lointain, pourtant c&amp;#8217;est la réalité que sont en train de vivre des millions de personnes dans le monde : leur existence même est menacée.
Que feriez-vous si vous ne pouviez, physiquement, plus vivre en France ?
Laissez-moi penser que les obsessions migratoires de politiciens et autres &lt;a href=&quot;https://www.telerama.fr/ecrans/dereglement-climatique-cnews-revele-les-impostures-du-giec-7009720.php&quot;&gt;consultants du bar du coin&lt;/a&gt; sont d&amp;#8217;un tel ridicule comparé à ce qui nous attend&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous sommes en avance sur les 1.5 degrés prévus par le GIEC: &lt;a href=&quot;https://www.france24.com/fr/info-en-continu/20240208-r%C3%A9chauffement-climatique-l-ann%C3%A9e-2024-d%C3%A9bute-par-de-nouveaux-records&quot;&gt;pour la première fois, les +1.5⁰ ont été dépassés pendant 12 mois consécutifs&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A 2 degrés, nous savons déjà que la sécurité alimentaire ne sera plus assurée, que des conflits liés aux migrations climatiques vont éclater, pour l&amp;#8217;accès aux ressources et pour justement empêcher les migrations de personnes qui cherchent simplement à survivre.
Fantasme ? Regardez par exemple &lt;a href=&quot;https://www.rfi.fr/fr/podcasts/le-monde-en-questions/20230603-afghanistan-iran-vers-une-guerre-de-l-eau&quot;&gt;ce qui se passe entre l&amp;#8217;Iran et l&amp;#8217;Afghanistan pour l&amp;#8217;accès à l&amp;#8217;eau potable&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A 2.5 degrés, certaines régions du monde, en particulier en zone tropicale, deviennent inhabitables.
Les rassuristes avancent que l&amp;#8217;homme a toujours su s&amp;#8217;adapter, mais &lt;a href=&quot;https://bonpote.com/rapport-de-synthese-du-giec-chaque-dixieme-de-degre-compte/&quot;&gt;il existe cependant des limites physiologiques&lt;/a&gt;, la réalité scientifique s&amp;#8217;impose à tous.
Au-delà d&amp;#8217;un certain seuil, la combinaison de la température et de l&amp;#8217;humidité ambiante &lt;a href=&quot;https://www.ouest-france.fr/leditiondusoir/2020-08-18/35-degres-de-temperature-humide-ce-seuil-mortel-pour-lhomme-nest-plus-une-fiction-af85e33a-7375-4821-b475-da6855c9c3ac&quot;&gt;rend inefficace le mécanisme de transpiration&lt;/a&gt;.
Nous mourrons, il ne s&amp;#8217;agit pas d&amp;#8217;une opinion, mais d&amp;#8217;une réalité devenue tristement célèbre l&amp;#8217;été dernier &lt;a href=&quot;https://www.sudouest.fr/culture/musique/une-jeune-femme-de-23-ans-meurt-pendant-le-concert-de-taylor-swift-au-bresil-17512330.php&quot;&gt;lors d&amp;#8217;un concert de Taylor Swift&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_de_la_difficulté_des_ordres_de_grandeur&quot;&gt;De la difficulté des ordres de grandeur&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un des problèmes majeurs du réchauffement climatique est qu&amp;#8217;il est, même en étant sensible au sujet, difficile de se rendre compte des ordres de grandeur.
J&amp;#8217;étais par exemple déjà sensibilisé au sujet, mais, malgré tout, je continuais à prendre l&amp;#8217;avion en particulier pour mon travail.
Je savais que l&amp;#8217;avion était mauvais pour le climat, mais je n&amp;#8217;avais aucune idée d&amp;#8217;à quel point : on &lt;em&gt;sait&lt;/em&gt; que c&amp;#8217;est mauvais, mais rares sont ceux qui nous donnent les ordres de grandeur.
On se retrouve ainsi avec des politiques qui nous incitent à éteindre nos appareils en veille mais nous proposent de faire un aller-retour à Rome pour 100€ ou moins par avion !
Des non-sens écologiques, mais pas économiques : un aller-retour Paris-Dubaï par exemple, c&amp;#8217;est l&amp;#8217;équivalent de votre budget carbone annuel selon les accords de Paris !
Des &lt;a href=&quot;https://co2.myclimate.org/fr/flight_calculators/new&quot;&gt;outils existent désormais pour évaluer votre impact&lt;/a&gt; et des activistes comme &lt;a href=&quot;https://bonpote.com/10-chiffres-a-connaitre-sur-lavion-et-le-climat/&quot;&gt;Bon Pote font un excellent travail pour décrire les problèmes inhérents à l&amp;#8217;industrie aéronautique&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Habitué des conférences à l&amp;#8217;international pour mon travail, ma prise de conscience sur ce sujet particulier fut aussi tardive que brutale. J&amp;#8217;en ai ai encore honte.
J&amp;#8217;ai cependant pris la décision, voici un peu plus de 4 ans, de ne plus prendre l&amp;#8217;avion et de n&amp;#8217;assister qu&amp;#8217;aux conférences auxquelles je peux me rendre par train.
C&amp;#8217;est pourtant un vœux pieux, puisque je reste un être humain : que ferais-je lorsque mon entreprise me donnera le choix entre prendre la porte ou donner une conférence à San Francisco, ou une réunion de travail au Maroc ?
Ce problème est aussi sujet de tensions familiales, entre les vœux légitimes de &quot;voyager&quot;, d&amp;#8217;explorer le monde et ses merveilles, et mon obstination à dire non.
Combien de temps résisterais-je à cette pression ?
Une bonne partie de ma carrière s&amp;#8217;est construite sur le fait de rencontrer des experts de mon domaine à l&amp;#8217;étranger, mais aussi à partager mes connaissances : je suis le fruit du réchauffement climatique.
Quelle légitimité ai-je à vous &quot;faire la morale&quot; et vous demander, à vous, d&amp;#8217;y renoncer ?
Qui suis-je pour refuser ce que j&amp;#8217;ai moi-même fait ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je n&amp;#8217;ai pas de bonne réponse à cette question, si ce n&amp;#8217;est de faire appel à votre sensibilité.
D&amp;#8217;autre part, je ne serai pas de ceux qui vous jugent pour vos choix : je suis le premier plein de contradictions et nous faisons, chacun, nos choix en fonction de ce que nous savons à un instant T, de nos contraintes, et finalement de nos convictions.
Pour certaines décisions, nous &lt;em&gt;avons le choix&lt;/em&gt; et certaines décisions seront plus faciles à prendre pour &lt;em&gt;vous&lt;/em&gt; que pour moi, et inversement !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il est bien plus facile pour un citadin de se séparer de son SUV que pour quelqu&amp;#8217;un qui n&amp;#8217;a pas accès aux transports au commun en zone rurale.
Inversement, manger local et faire travailler producteurs locaux est plus simple pour un rural qu&amp;#8217;un citadin.
Chacun de nous, à notre échelle, faisons des choix qui nous semblent opportuns compte-tenu de nos situations personnelles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prenons donc ces ordres de grandeur en exemple.
Pour respecter les accords de Paris et limiter le réchauffement climatique à 2 degrés, notre empreinte carbone, par personne, doit tomber à 2 tonnes par an.
A ce jour, les estimations varient, mais l&amp;#8217;empreinte carbone d&amp;#8217;un français est de l&amp;#8217;ordre de 10 tonnes par an.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/empreinte-carbone.webp&quot; alt=&quot;empreinte carbone&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En France, 31% des émissions sont liées au transport, donc à la voiture individuelle et aux transports de marchandises, c&amp;#8217;est dire si le sujet de la voiture est important.
Pourtant, que constate-t-on ?
L&amp;#8217;automobile est le &lt;a href=&quot;https://car-use.org/la-publicite-dans-lautomobile-hier-et-aujourdhui/&quot;&gt;2d plus gros contributeur à la publicité en France&lt;/a&gt;, avec environ 1500€ de budget communication &lt;em&gt;par voiture&lt;/em&gt;.
Notre Président &lt;a href=&quot;https://www.numerama.com/sciences/1519938-emmanuel-macron-aime-la-bagnole-ce-nouveau-rapport-sur-le-climat-lui-donne-tort.html&quot;&gt;aime la bagnole&lt;/a&gt; et envoie un message désastreux.
Bruno Le Maire, devant trouver 10 milliards d&amp;#8217;économies, &lt;a href=&quot;https://www.huffingtonpost.fr/economie/article/le-gouvernement-coupe-10-milliards-d-euros-dans-son-budget-l-environnement-contribue-pour-20_230180.html&quot;&gt;choisit de le faire sur l&amp;#8217;environnement et les mobilités&lt;/a&gt;.
En clair, on nous vend des voitures au lieu de &lt;a href=&quot;https://www.v-logistique.com/2021-10-22/le-velo-vs-la-voiture-un-ecart-colossal-d-emissions-de-co2&quot;&gt;nous vendre des vélos électriques, dont l&amp;#8217;empreinte carbone est 20 fois inférieure&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce &lt;a href=&quot;https://ourworldindata.org/grapher/co-emissions-per-capita?time=2022&quot;&gt;site&lt;/a&gt; montre l&amp;#8217;évolution de l&amp;#8217;empreinte carbone par tête et par pays, depuis le début de l&amp;#8217;ère industrielle.
Il y a 2 choses importantes à comprendre :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;l&amp;#8217;empreinte carbone est directement corrélée au niveau de vie des habitants. Plus on est riche, plus on consomme. Plus on consomme, plus notre empreinte est forte. L&amp;#8217;empreinte carbone est 10 à 50 fois plus forte dans les pays industrialisés qu&amp;#8217;en Afrique. Ainsi, il est complètement faux d&amp;#8217;affirmer, &lt;a href=&quot;https://vert.eco/articles/au-mepris-du-reel-nicolas-sarkozy-agite-la-menace-dune-explosion-demographique-pour-expliquer-la-crise-climatique&quot;&gt;comme Nicolas Sarkozy&lt;/a&gt;, que la crise démographique est responsable de la crise climatique. Ça n&amp;#8217;est pas le nombre de personnes qui compte, mais leur capacité à consommer. Diminuer la population serait donc une solution&amp;#8230;&amp;#8203; à condition de le faire dans les pays développés !&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;l&amp;#8217;empreinte carbone est essentiellement impactée par la consommation d&amp;#8217;énergies fossiles (pétrole et charbon). C&amp;#8217;est ce qui explique que l&amp;#8217;empreinte carbone d&amp;#8217;un français est plus faible que celle d&amp;#8217;un allemand ou d&amp;#8217;un polonais : là où ils utilisent des centrales à charbon pour se chauffer et faire tourner leurs industries, nous avons des centrales nucléaires.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sur ce sujet du nucléaire, soyons clairs : je suis écolo et pour.
Lorsqu&amp;#8217;on connaît ces ordres de grandeurs, lorsqu&amp;#8217;on sait qu&amp;#8217;environ 240 000 personnes meurent en Europe tous les ans à cause de la pollution atmosphérique principalement liée à la combustion de charbon, la position écologique anti-nucléaire traditionnelle est difficilement tenable.
Cette position anti-nucléaire, je l&amp;#8217;avais de part de mes lectures lorsque j&amp;#8217;étais gamin (Pif&amp;#8217;Gadget, Greenpeace, des positions essentiellement liées à la peur du nucléaire, des accidents et de leurs terribles conséquences.
Ça, c&amp;#8217;était avant d&amp;#8217;avoir pris le temps d&amp;#8217;étudier le sujet.
J&amp;#8217;ai depuis largement révisé ma position et suis convaincu qu&amp;#8217;on ne pourra pas s&amp;#8217;en sortir sans nucléaire.
Il d&amp;#8217;ailleurs assez ironique de constater que &lt;a href=&quot;https://theconversation.com/tchernobyl-35-ans-apres-laccident-nucleaire-decouvrez-comment-la-nature-y-a-repris-ses-droits-118082&quot;&gt;la biodiversité a fortement augmenté à Tchernobyl&lt;/a&gt;, depuis que la zone n&amp;#8217;est plus occupée, de quoi être optimiste sur la résilience des écosystèmes si nous devions disparaître !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci ne veut pas dire qu&amp;#8217;on ne peut pas développer les énergies renouvelables, bien au contraire, mais il faut encore une fois avoir les ordres de grandeur en tête.
Vous trouverez des chiffres différents selon les estimations plus ou moins pessimistes (notamment le &lt;a href=&quot;https://fr.wikipedia.org/wiki/Facteur_de_charge_(%C3%A9lectricit%C3%A9)&quot;&gt;facteur de charge&lt;/a&gt;), mais il faut comprendre que pour remplacer 1 seul réacteur nucléaire, il faut &lt;a href=&quot;https://www.liberation.fr/checknews/2018/06/07/est-il-vrai-qu-il-faudrait-7000-eoliennes-pour-remplacer-fessenheim_1656464/&quot;&gt;environ 1000 éoliennes&lt;/a&gt; ou &lt;a href=&quot;https://fr.quora.com/Combien-de-panneaux-solaires-faut-il-en-moyenne-pour-remplacer-une-centrale-nucl%C3%A9aire&quot;&gt;55 km² de panneaux solaires&lt;/a&gt;.
Nous avons 56 réacteurs en France&amp;#8230;&amp;#8203;
Sans réduire notre consommation électrique, ceci signifie que nous devons exacerber encore plus la concurrence pour l&amp;#8217;occupation des sols : doit-on s&amp;#8217;en servir pour produire de la nourriture, de l&amp;#8217;énergie, du logement ou la laisser libre pour la biodiversité ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Est-il dès lors si surprenant que l&amp;#8217;Allemagne ait dù &lt;a href=&quot;https://www.youtube.com/watch?v=V0rdohof74A&quot;&gt;raser des villages entiers pour exploiter le charbon nécessaire à la remise en marche de ses centrales&lt;/a&gt; ?
Une bombe climatique !
Doit-on ensuite s&amp;#8217;étonner que ces exemples soient repris par les réactionnaires pour décrédibiliser &lt;em&gt;toute&lt;/em&gt; action de protection de l&amp;#8217;environnement ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Voilà le noeud du problème : notre société moderne est bâtie sur la consommation &lt;em&gt;massive&lt;/em&gt; d&amp;#8217;énergie, en particulier du pétrole, et à moins de réduire drastiquement cette consommation, nous ne pourrons tenir nos engagements.
A l&amp;#8217;heure actuelle, il faudrait réduire de 5% par an notre consommation d&amp;#8217;énergies fossiles pour y arriver.
Cette consommation étant directement corrélée à la sacro-sainte croissance, il s&amp;#8217;agit ni plus ni moins que d&amp;#8217;avoir l&amp;#8217;équivalent d&amp;#8217;un COVID, tous les ans !
Nos politiques &lt;a href=&quot;https://www.liberation.fr/environnement/climat/inaction-climatique-de-la-france-les-associations-de-laffaire-du-siecle-saisissent-le-conseil-detat-20240222_ECKH6LZXRVBIHF3DUL3J3M6SQQ/&quot;&gt;ont déja renoncé, personne n&amp;#8217;étant prêt aux sacrifices que celà implique&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
On m&amp;#8217;a posé la question de la chaîne d&amp;#8217;approvisionnement d&amp;#8217;uranium, qui peut être problématique. C&amp;#8217;est vrai, mais uniquement si nous restons à cette génération de réacteurs. La 4ème génération, les &lt;a href=&quot;https://fr.wikipedia.org/wiki/Surg%C3%A9n%C3%A9ration&quot;&gt;surgénérateurs&lt;/a&gt; sont capables d&amp;#8217;utiliser les produits dérivés de la fission et nous donnent suffisamment de ressources pour des siècles de consommation. Pourtant, ce sont tous les expérimentateurs qui ont été mis à l&amp;#8217;arrêt (&lt;a href=&quot;https://fr.wikipedia.org/wiki/Superph%C3%A9nix&quot;&gt;Superphénix&lt;/a&gt; ou &lt;a href=&quot;https://fr.wikipedia.org/wiki/Astrid_(r%C3%A9acteur)&quot;&gt;Astrid&lt;/a&gt;). Un gâchis dénoncé par &lt;a href=&quot;https://www.youtube.com/watch?v=L0ZX3moD_mQ&quot;&gt;Yves Bréchet lors de son audition au Sénat&lt;/a&gt;.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;De sacrifices, pourtant, c&amp;#8217;est de cela qu&amp;#8217;il s&amp;#8217;agit.
Sacrifier nos générations futures, ou sacrifier notre mode de vie.
Nous vivons toujours selon le mythe d&amp;#8217;une croissance infinie : toute notre société est bâtie sur ce seul concept économique qui n&amp;#8217;a aucun sens physique.
La réalité physique des choses est pourtant implacable : il n&amp;#8217;existe pas de croissance infinie dans un monde fini.
Là encore, il est indispensable de parler d&amp;#8217;ordres de grandeur : une croissance à 2% signifie un doublement de la valeur tous les 36 ans.
Qui dit valeur dit production, dit consommation d&amp;#8217;énergie, dit impact sur l&amp;#8217;environnement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dit autrement, la croissance est une courbe exponentielle : il s&amp;#8217;agit du genre de courbes que l&amp;#8217;on ne souhaite pas voir.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/annual-co2-emissions-per-country.png&quot; alt=&quot;annual co2 emissions per country&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;N&amp;#8217;est-il pas inquiétant de constater que dans ce graphique, des crises majeures comme les chocs pétroliers des années 70 ou le COVID n&amp;#8217;ont eu que peu ou pas d&amp;#8217;influence sur notre consommation ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une autre visualisation de la notion d&amp;#8217;exponentielle, c&amp;#8217;est celle des anomalies de température, produite par la NASA.
Une animation que je trouve particulièrement efficace pour comprendre l&amp;#8217;effet d&amp;#8217;emballement :&lt;/p&gt;
&lt;/div&gt;
 &lt;video width=&quot;800&quot; height=&quot;480&quot; controls&gt;
  &lt;source src=&quot;https://melix.github.io/blog/img/climate/temp_spiral.webm&quot; type=&quot;video/webm&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette exponentielle explique pourquoi le développement des énergies renouvelables ne s&amp;#8217;est pas faite au détriment des énergies fossiles : elle s&amp;#8217;est faite essentiellement en &lt;em&gt;complément&lt;/em&gt;, parce que nous avons toujours besoin de plus d&amp;#8217;énergie pour maintenir cette croissance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, si la consommation de charbon dans la production énergétique mondiale baisse en pourcentage, &lt;a href=&quot;https://www.connaissancedesenergies.org/charbon-un-nouveau-pic-de-la-consommation-mondiale-attendu-en-2023-et-apres-240108&quot;&gt;le volume n&amp;#8217;a jamais été aussi élevé&lt;/a&gt; !
Une mauvaise nouvelle à cependant relativiser, puisque &lt;a href=&quot;https://www.latribune.fr/climat/energie-environnement/pour-la-premiere-fois-l-aie-anticipe-une-baisse-structurelle-de-la-demande-mondiale-de-charbon-985771.html&quot;&gt;la production de charbon baisse&lt;/a&gt; : en effet, dans des pays tels que l&amp;#8217;Allemagne, les renouvelables sont destinés à remplacer les centrales à charbon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le problème des courbes comme celles-ci est que les prévisions deviennent presque impossible à formuler, on entre dans le domaine de l&amp;#8217;inconnu, et les esprits scientifiques comme moi n&amp;#8217;aiment pas cela.
&lt;a href=&quot;https://fr.wikipedia.org/wiki/Serge_Zaka&quot;&gt;Serge Zaka&lt;/a&gt;, docteur en agroclimatologie, décrit des &lt;a href=&quot;https://www.facebook.com/permalink.php?story_fbid=pfbid0263SryV9KtpZ6TARDW6uZtf2xGbWq3J5szZ3kJqzx1tw1jhNDGTp6rxBKbMVMeFc1l&amp;amp;id=61550647585914&quot;&gt;phénomènes de réchauffement des océans&lt;/a&gt; statistiquement impossibles (autrement dit, les marges dépassent ce que la statistique classique considère comme possible).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette question de la croissance, pourtant, est au cœur de notre survie.
Attention, je ne parle pas de la survie de l&amp;#8217;espèce, ni même de &quot;sauver la planète&quot;.
En effet, même en étant pessimiste, je pense que l&amp;#8217;espèce humaine survivra.
En revanche, ne comptez pas sur moi pour vous dire &lt;em&gt;combien&lt;/em&gt; survivront : mon intuition, compte-tenu des paramètres dont nous parlons ici, est que nous risquons de voir une nouvelle crise majeure.
Et quand bien même l&amp;#8217;espèce humaine ne survivrait pas, la vie, elle, continuera sans nous : elle existait avant, elle existera après.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_cest_lhistoire_dun_skieur_qui_se_répétait_jusquici_tout_va_bien&quot;&gt;C&amp;#8217;est l&amp;#8217;histoire d&amp;#8217;un skieur qui se répétait &quot;jusqu&amp;#8217;ici tout va bien&quot;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/la-haine.jpg&quot; alt=&quot;la haine&quot; width=&quot;300&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour prendre une analogie, nous sommes un peu dans la situation d&amp;#8217;un skieur du dimanche : il descend sa piste, il à se sent à l&amp;#8217;aise.
Il accélère, prend plaisir, jusqu&amp;#8217;à se rendre compte qu&amp;#8217;il a pris trop de vitesse, que la pente est bien trop raide et qu&amp;#8217;il ne peut plus maîtriser sa course.
En bas, un croisement, d&amp;#8217;autres skieurs, il est trop tard pour s&amp;#8217;arrêter et il n&amp;#8217;y a que 2 solutions :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;virer, se laisser tomber, quitte à se casser une jambe, pour éviter le groupe&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;continuer et entrer en collision, en entraînant de nombreuses autres personnes dans la chute et potentiellement de nombreuses victimes&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;M&amp;#8217;est avis que beaucoup de personnes choisissent instinctivement la 2ème solution, parce que la première n&amp;#8217;est pas confortable et que notre instinct de préservation nous joue des tours : incapable d&amp;#8217;anticiper des conséquences encore pires à long terme, notre espèce se mure dans le déni et choisit la solution la moins logique.
Pire, notre tendance naturelle est, souvent paradoxalement de bonne foi, de déresponsabiliser.
Les exemples sont nombreux : mettre des radars automatiques au lieu d&amp;#8217;apprendre à respecter les limites, demander aux enfants de mettre des gilets jaunes au lieu de sécuriser les routes, dire aux filles de se couvrir au lieu de demander aux garçons de cesser de les voir comme des objets sexuels, demander d&amp;#8217;éteindre vos box internet au lieu de prendre votre vélo pour aller chercher du pain&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_rassurisme_et_techno_solutionnisme&quot;&gt;Rassurisme et techno-solutionnisme&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Maintenant que le réchauffement climatique est palpable et subi par les plus sceptiques d&amp;#8217;entre nous, un nouveau mal est en marche : le rassurisme.
Se substituant au climato-scepticisme, il consiste à affirmer que nous nous en sortirons toujours, que l&amp;#8217;homme s&amp;#8217;est toujours adapté, que nous trouverons des solutions techniques, et cætera, et cætera.
Le rassurisme est une plaie parce qu&apos;&lt;strong&gt;il incite à l&amp;#8217;inaction&lt;/strong&gt;.
Agréable discours à entendre, il est le parfait compagnon du status quo, sous couvert de discours &quot;de bon sens&quot;, mais aussi un risque encore plus grand pour l&amp;#8217;avenir.
Je classe dans le rassurisme le discours techno-solutioniste que nous entendons de plus en plus.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prenons par exemple l&amp;#8217;idée souvent commentée de la séquestration du carbone : pourquoi ne pourrions-nous pas l&amp;#8217;extraire de l&amp;#8217;atmosphère ?
A priori, l&amp;#8217;idée n&amp;#8217;est pas idiote, si on peut le faire il serait idiot de s&amp;#8217;en passer.
Pourtant, il suffit d&amp;#8217;un tout petit peu de recherche pour se rendre compte des problèmes.
Lorsqu&amp;#8217;on parle de concentrations de CO², nous parlons de &lt;em&gt;parties par million&lt;/em&gt;.
Par exemple, 200ppm, ce sont 200 molécules de CO² sur 1 million : c&amp;#8217;est une concentration extrêmement faible, mais qui a des effets dévastateurs.
Si vous avez quelques souvenirs de physique, je vous conseille d&amp;#8217;ailleurs cette excellente &lt;a href=&quot;https://www.youtube.com/watch?v=ewc8FBtEKPs&quot;&gt;vidéo de Science Etonnante sur les mécanismes du réchauffement et le mythe de la saturation du réchauffement&lt;/a&gt;.
Si tant est que nous disposions d&amp;#8217;une technologie de &quot;nettoyage&quot;, il faudrait brasser une quantité d&amp;#8217;air phénoménale pour l&amp;#8217;extraire et pour brasser cet air, il faudrait une quantité non négligeable d&amp;#8217;énergie&amp;#8230;&amp;#8203;
En clair, il s&amp;#8217;agit donc souvent plus de &quot;coups de com&apos;&quot; d&amp;#8217;entreprises cherchant avant tout à faire de l&amp;#8217;argent sur le dos du climat, peu recommandables&amp;#8230;&amp;#8203; mais pour lesquels des investisseurs peuvent se laisser séduire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un autre exemple, c&amp;#8217;est la &lt;a href=&quot;https://www.capital.fr/economie-politique/pourquoi-les-projets-delon-musk-pour-rendre-mars-vivable-ne-sont-pas-concretement-faisables-158509&quot;&gt;la colonisation de Mars&lt;/a&gt;, annoncée par Elon Musk.
Peut-on être sérieux seulement 5 minutes ?
Il n&amp;#8217;est pas surprenant que les seuls qui y croient soient des économistes, c&amp;#8217;est avant tout le modèle de la fuite en avant : puisqu&amp;#8217;on ne peut pas sauver notre planète, rendons-en une autre vivable !
L&amp;#8217;idée est d&amp;#8217;autant plus ridicule qu&amp;#8217;on ne sait même pas contrôler le climat ici, en premier lieu lutter contre le réchauffement climatique, alors que dire lorsque l&amp;#8217;on parle de changer le climat d&amp;#8217;une planète dont on ne sait presque rien&amp;#8230;&amp;#8203;
C&amp;#8217;est une chose que de vouloir fouler Mars du pied, s&amp;#8217;en est une autre que de la terraformer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais un des problèmes de la croissance et de l&amp;#8217;évolution de la technologie et de l&amp;#8217;information, c&amp;#8217;est qu&amp;#8217;elle rend possible des actions individuelles aux conséquences potentiellement catastrophiques, au premier rang desquelles la géoingénierie.
Ainsi, un &lt;a href=&quot;https://climate.benjames.io/someone-is-going-to-dim-the-sun/&quot;&gt;article particulièrement inquiétant&lt;/a&gt; montre que nous disposons de moyens de diffuser économiquement du sulfure dans l&amp;#8217;atmosphère, pour refroidir l&amp;#8217;atmosphère&apos;.
Même avec des conséquences terrifiantes, telles que des pluies acides, ou le simple fait qu&amp;#8217;arrêter d&amp;#8217;en diffuser entraînerait un réchauffement massif encore plus grand, le fait est que ça pourrait fonctionner en pratique.
Nous sommes donc en plein dans ce que j&amp;#8217;expliquais plus haut : plutôt que de résoudre le problème à sa source, on continue, quitte à avoir des conséquences bien pires plus tard.
Lorsqu&amp;#8217;une technologie est disponible, elle est utilisée.
La question n&amp;#8217;est donc pas de savoir SI, mais QUAND elle sera utilisée, soit par un riche milliardaire qui souhaite continuer à faire du profit en dépit du bon sens, ou d&amp;#8217;un Etat qui lutte pour sa survie.
Si vous vous rappelez de &lt;a href=&quot;https://fr.wikipedia.org/wiki/Horloge_de_la_fin_du_monde&quot;&gt;l&amp;#8217;horloge de l&amp;#8217;apocalypse&lt;/a&gt;, il me semble qu&amp;#8217;on se rapproche dangereusement de minuit&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;autre effet pervers du techno-solutionnisme, c&amp;#8217;est que si tant est qu&amp;#8217;il fonctionne, il n&amp;#8217;incite pas à la sobriété.
Ainsi, toutes les évolutions technologiques qui ont permis de faire des économies n&amp;#8217;ont in fine pas eu pour conséquence de réduire la consommation.
Par exemple, les moteurs thermiques sont aujourd&amp;#8217;hui beaucoup plus efficaces qu&amp;#8217;avant, mais les économies ont servi à augmenter l&amp;#8217;autonomie ou à avoir des voitures plus grosses : c&amp;#8217;est &lt;a href=&quot;https://fr.wikipedia.org/wiki/Effet_rebond_(%C3%A9conomie)&quot;&gt;l&amp;#8217;effet rebond&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, toutes ces évolutions technologiques ne sont en pratique là que pour supporter un modèle de consommation constant.
Un autre exemple ?
Le rendement à l&amp;#8217;hectare de la production agricole a été multiplié 3 depuis 1960, par plus de 10 depuis le début de l&amp;#8217;ère industrielle :&lt;/p&gt;
&lt;/div&gt;
&lt;iframe src=&quot;https://donnees.banquemondiale.org/share/widget?indicators=AG.YLD.CREL.KG&quot; width=&apos;450&apos; height=&apos;300&apos; frameBorder=&apos;0&apos; scrolling=&quot;no&quot; &gt;&lt;/iframe&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On se rend bien compte du mensonge qui consiste à dire qu&amp;#8217;il faut bien continuer ce modèle pour nourrir la planète : nous pourrions utiliser les gains de productivité à l&amp;#8217;hectare pour nourrir plus de monde mais nous avons choisi de les investir dans des biocarburants pour faire rouler des voitures, ou dans de la production industrielle de produits transformés qui menacent notre santé.
Pour autant, les revenus des agriculteurs ne cessent de chuter, les famines n&amp;#8217;ont pas disparu (essentiellement pour des questions de logistique) et les maladies cardiovasculaires explosent.
Nous produisons largement plus que ce que dont nous avons besoin pour survivre, mais nous &quot;produisons de la croissance&quot; en &lt;em&gt;transformant&lt;/em&gt; les produits.
Là où au début du siècle, l&amp;#8217;essentiel de la consommation se faisait du produit brut au consommateur, désormais l&amp;#8217;essentiel se fait par des produits transformés.
L&amp;#8217;abondance est illustrée par ce graphique représentant l&amp;#8217;apport calorique par habitant :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/daily-per-capita-caloric-supply.png&quot; alt=&quot;daily per capita caloric supply&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A celles et ceux qui répondront que plus d&amp;#8217;apport calorique c&amp;#8217;est une meilleure santé, rappelons que nous avons besoin d&amp;#8217;entre 2000 et 2500 calories par jour, un seuil qui a été franchi au début des années 1820.
Depuis, nous sommes bien au-delà, ce qui explique notamment l&amp;#8217;explosion de l&amp;#8217;obésité et des maladies cardiovasculaires (en combinaison avec la sédentarité permise par l&amp;#8217;exploitation des machines).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, la croissance n&amp;#8217;est pas nécessairement synonyme de progrès : au delà d&amp;#8217;un certain seuil, elle devient maladive et entraîne plus de maux que de bien.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les prémisses de cette constatation ne datent pas d&amp;#8217;hier, le &lt;a href=&quot;https://www.rfi.fr/fr/connaissances/20220819-il-y-a-50-ans-le-rapport-meadows-posait-des-limites-%C3%A0-la-croissance&quot;&gt;club de Rome&lt;/a&gt; s&amp;#8217;en faisait écho il y a 50 ans déja.
De nos jours, rares encore sont les économistes qui défendent la décroissance.
En France, des chercheurs comme &lt;a href=&quot;https://www.seuil.com/ouvrage/ralentir-ou-perir-timothee-parrique/9782021508093&quot;&gt;Timothée Parrique&lt;/a&gt; montrent avec brio que la décroissance ne peut plus être considérée comme un gros mot.
Au contraire, elle devient nécessaire, comme le laisse entendre ce titre &quot;ralentir ou périr&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il ne faut pas non plus confondre le techno-solutionnisme avec l&amp;#8217;utilisation des techniques permettant de limiter l&amp;#8217;impact de notre consommation.
Certains outils seront indispensables, mais si nous devons répondre à une solution d&amp;#8217;urgence, il est préférable de le faire avec les technologies dont on dispose, pas de celles dont on ne sait pas si elles seront disponibles dans 10 ans.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_pourquoi_un_effondrement&quot;&gt;Pourquoi un effondrement ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous l&amp;#8217;avons vu, la conjoncture n&amp;#8217;est pas favorable, loin de là.
Nous savons, nos gouvernements savent, mais rien ne change.
N&amp;#8217;était-ce pas Emmanuel Macron qui nous a &lt;a href=&quot;https://www.lemonde.fr/election-presidentielle-2022/article/2022/04/16/emmanuel-macron-promet-a-marseille-un-second-mandat-qui-sera-ecologique-ou-ne-sera-pas_6122484_6059010.html&quot;&gt;promis que son quinquennat &quot;sera écologique ou ne sera pas&quot;&lt;/a&gt; ?
Nous avons la réponse : après le une &lt;a href=&quot;https://www.ledauphine.com/environnement/2021/07/07/que-reste-t-il-des-propositions-de-la-convention-climat&quot;&gt;convention citoyenne sur le Climat vidée de sa substance&lt;/a&gt;, après &lt;a href=&quot;https://www.huffingtonpost.fr/environnement/video/sur-les-pesticides-gabriel-attal-cede-a-une-revendication-des-syndicats-agricoles-contre-les-ong-ecologistes_230132.html&quot;&gt;le sacrifice de l&amp;#8217;écologie au profit des agroindustriels qui nous confortent dans ce modèle&lt;/a&gt;, il n&amp;#8217;y a a que du cynisme dans les décisions politiques.
Même au niveau local, dans ma commune, la majorité se gausse à coups de croissance verte, un concept qui ne parle qu&amp;#8217;aux économistes et qui n&amp;#8217;a &lt;a href=&quot;https://www.polytechnique-insights.com/dossiers/economie/regards-croises-sur-la-decroissance-une-vision-departagee/la-croissance-verte-est-une-illusion/&quot;&gt;jamais démontré le moindre succès&lt;/a&gt;.
Encore une fois, il n&amp;#8217;y a rien de surprenant : un niveau de base en mathématiques ou de physique suffit à comprendre qu&amp;#8217;on ne peut faire de croissance sans sacrifier de ressources, ce qui se traduit soit par de la pollution, soit par du réchauffement climatique.
Dans ma commune, on &lt;a href=&quot;https://mvea85.fr/sites/blog/2023_10_06_non_demenagement_leclerc&quot;&gt;construit encore des supermarchés en périphérie comme dans les années 70&lt;/a&gt; et on moque les écologistes &quot;décroissants&quot;, &quot;contre l&amp;#8217;emploi&quot; et &quot;pour l&amp;#8217;insécurité&quot;.
Qu&amp;#8217;importe l&amp;#8217;état catastrophique des cours d&amp;#8217;eau, que l&amp;#8217;eau doivent être importée de Loire-Atlantique pour subvenir aux besoins d&amp;#8217;industries agroalimentaires locales bien connues, puisqu&amp;#8217;on a la croissance !
Qu&amp;#8217;importe que l&amp;#8217;on doive construire sur des terres agricoles pour loger tous les néo-ruraux attirés par la croissance économique du territoire&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous constatons là que malgré toutes les informations disponibles, nous sommes dans la situation du skieur qui ne peut plus s&amp;#8217;arrêter; il y aura des dégâts !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cependant, pas de quoi prophétiser un effondrement civilisationnel, me direz-vous.
Certes, mais il y a plus : c&amp;#8217;est la conjonction de facteurs qui peut entraîner notre chute.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous avons mentionné que dans le dérèglement climatique, l&amp;#8217;essentiel du problème était concentré autour des énergies fossiles.
Cependant, d&amp;#8217;autres problèmes d&amp;#8217;ampleur sont eux aussi liés à notre modèle de développement : l&amp;#8217;effondrement de la biodiversité par exemple.
Nous sommes entrés dans une nouvelle phase d&amp;#8217;extinction de masse, tellement bien documentée qu&amp;#8217;elle porte un nom: &lt;a href=&quot;https://fr.wikipedia.org/wiki/Extinction_de_l%27Holoc%C3%A8ne&quot;&gt;l&amp;#8217;extinction de l&amp;#8217;Holocène&lt;/a&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/global-living-planet-index.png&quot; alt=&quot;global living planet index&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En 50 ans, plus de la moitié du monde sauvage a disparu.
Je ne sais pas si vous vous rendez bien compte : l&amp;#8217;homme est présent sur Terre depuis plus de 4 millions d&amp;#8217;années, Homo Sapiens depuis 300000 ans environ, et en &lt;strong&gt;seulement 50 ans&lt;/strong&gt;, nous avons détruit plus de la moitié des espèces.
Pour la biodiversité marine, la situation est encore pire, avec la surpêche, l&amp;#8217;augmentation de la température et l&amp;#8217;acidification des océans.
Depuis plus de 6 mois, nous vivons une véritable &lt;a href=&quot;https://www.fondationdelamer.org/canicule-marine-une-catastrophe-silencieuse/&quot;&gt;canicule marine&lt;/a&gt;, mais qui en a entendu parler ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Or, l&amp;#8217;homme fait partie d&amp;#8217;un écosystème : nous vantons notre adaptabilité, mais nous sommes les premiers dépendants de notre environnement.
Le détruire, c&amp;#8217;est directement menacer notre survie : il faut être fou pour croire que l&amp;#8217;homme peut survivre seul.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Devant l&amp;#8217;opposition à la décroissance, ou même simplement les appels à la sobriété, les discours les plus réactionnaires sont en marche.
Il n&amp;#8217;y a pas de quoi être optimiste, lorsqu&amp;#8217;en France, un ministre &lt;a href=&quot;https://basta.media/qui-sont-les-veritables-terroristes-de-l-environnement-ecoterroristes-Darmanin-Soulevements-de-la-terre-Zad-agrobusiness-multinationales-fossiles-criminels-climatiques&quot;&gt;traite des militants écologistes d&amp;#8217;éco-terroristes&lt;/a&gt;, mais en même temps, soutient des agro-industriels qui &lt;a href=&quot;https://www.lefigaro.fr/actualite-france/agriculteurs-en-colere-ce-que-l-on-sait-sur-l-incendie-d-un-batiment-de-la-mutualite-sociale-agricole-a-narbonne-20240126&quot;&gt;mettent le feu à des mutuelles&lt;/a&gt;&amp;#8230;&amp;#8203;
Là encore on pourrait croire à de l&amp;#8217;ignorance, mais il s&amp;#8217;agit d&amp;#8217;un cynisme sans nom : tous savent pertinemment ce qui se profile, mais aucun n&amp;#8217;a le courage politique pour faire ce qui est vraiment nécessaire : un nouveau modèle de société basé sur la sobriété.
Que dire d&amp;#8217;un pays où l&amp;#8217;on s&amp;#8217;émeut plus facilement d&amp;#8217;une boîte de soupe versée sur un tableau protégé derrière une vitre en verre, que de &lt;a href=&quot;https://www.radiofrance.fr/franceculture/podcasts/la-revue-de-presse-internationale/la-revue-de-presse-internationale-emission-du-mardi-20-juin-2023-1146234&quot;&gt;plusieurs centaines de morts en Inde suite à la canicule&lt;/a&gt;&amp;#8230;&amp;#8203;
Pas vraiment de quoi être optimiste.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On pourrait s&amp;#8217;arrêter là mais d&amp;#8217;autres signaux sont tout aussi inquiétants.
Je rappelais par exemple à quel point notre société moderne est basée sur les énergies fossiles.
Le graphique ci-dessous montre par exemple la répartition de la consommation énergétique par filière :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/climate/energie-par-filiere.png&quot; alt=&quot;energie par filiere&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La baisse en 2020 est liée au COVID, mais ne nous y trompons pas : à l&amp;#8217;échelle mondiale, les énergies fossiles dominent : les renouvelables représentent une part croissante de la production, mais ne sont comparables qu&amp;#8217;au parc nucléaire, les énergies fossiles sont largement dominantes.
Dans ce portrait, la situation du pétrole est plus critique : nous savons que les réserves s&amp;#8217;épuisent.
Que l&amp;#8217;on décide de s&amp;#8217;en passer volontairement ou non, nous arriverons avant la fin du siècle à la fin du pétrole.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Or, dans de nombreux domaines, nous sommes complètement dépendants du pétrole, non pas en tant que source d&amp;#8217;énergie, mais de matière première :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pharmacologie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;agriculture (machines, mais aussi engrais)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;santé&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;textiles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cosmétiques&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il ne vous aura pas échappé que l&amp;#8217;Europe ne dispose pas ou peu de cette ressource.
Préférons-nous continuer à brûler ce qui nous reste pour voyager pour 500€ à l&amp;#8217;autre bout du monde, ou pour produire notre nourriture et fabriquer nos médicaments ?
Mon choix est vite fait&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A court ou moyen terme, la dépendance de l&amp;#8217;Europe au pétrole signifiera un asservissement aux pays qui en disposent (si tant est qu&amp;#8217;ils soient disposés à nous en vendre).
Sachant que ces pays ne sont pas ce qu&amp;#8217;il y a de plus démocratique, la question du respect des droits humains pourrait à moyen terme devenir un vague souvenir.
Dès lors quels choix s&amp;#8217;offriront à nous ? Entrer en guerre pour leur &quot;voler&quot; ces ressources ? Les forcer à nous en vendre ? A quel prix ? Comment ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le remplacement du pétrole en tant que source d&amp;#8217;énergie est possible mais requiert une électrification massive de nos moyens de subsistance (transports, machines outils, industries, &amp;#8230;&amp;#8203;) et une relocalisation de la production, le transport maritime dépendant essentiellement de cette ressource.
Or, qui dit électrification dit augmentation de la production.
De quels moyens disposons nous pour remplacer une telle quantité d&amp;#8217;énergie ?
L&amp;#8217;écologie n&amp;#8217;est jamais aussi mauvaise que lorsqu&amp;#8217;elle ignore la réalité physique des choses.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les pays qui disposent de ces ressources, donc, ne sont pas particulièrement amicaux.
Nous parlons de pays dont les actions récentes n&amp;#8217;augurent pas d&amp;#8217;un avenir radieux pour l&amp;#8217;Europe, mais aussi pour leurs propres populations : la Russie, la Chine, &amp;#8230;&amp;#8203;
La Russie, qui ne cesse d&amp;#8217;étendre son influence sur un continent Africain avide de &quot;revanche&quot; sur la colonisation et l&amp;#8217;exploitation de leurs ressources par l&amp;#8217;Occident.
Certes la Russie n&amp;#8217;est pas animée par la bonté de réparer les erreurs de l&amp;#8217;Occident, elle souhaite tout autant s&amp;#8217;accaparer les ressources minières du continent et par là donc disposer de moyens de pression&amp;#8230;&amp;#8203; pour gagner sa &lt;a href=&quot;https://www.institutmontaigne.org/expressions/le-monde-vu-dailleurs-le-choc-des-civilisations-une-version-russe&quot;&gt;&quot;guerre civilisationnelle&quot;&lt;/a&gt;, mais le message est passé, &lt;a href=&quot;https://www.challenges.fr/entreprise/defense/l-armee-francaise-va-quitter-le-niger-apres-le-burkina-le-mali-et-la-centrafrique_868471&quot;&gt;la France doit s&amp;#8217;en aller&lt;/a&gt; !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette guerre civilisationnelle, des gens comme moi y participent malgré eux.
Ceux qui me connaissent savent à quel point, notamment, je lutte contre mon envie de quitter mon métier.
A vrai dire, si je n&amp;#8217;avais ni famille, ni crédits sur le dos (comme tout le monde), je crois que j&amp;#8217;aurais déjà abandonné ce qui est pourtant une de mes passions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En effet, en tant que développeur, non seulement je contribue massivement au réchauffement climatique (le numérique représente une part de la consommation d&amp;#8217;énergie mondiale en explosion, notamment à cause de l&amp;#8217;explosion du nombre de terminaux), mais j&amp;#8217;ai aussi donné des outils de manipulation de masse, utilisés comme tels, par des puissances qui cherchent à nous déstabiliser.
Les réseaux sociaux, notamment, sont devenus de véritables poubelles où les idées complotistes, antivax, climatosceptiques sont promues bien plus que les autres.
Les idées dites &quot;de droite&quot; sont &lt;a href=&quot;https://www.lemonde.fr/pixels/article/2021/10/22/une-etude-de-twitter-montre-que-son-algorithme-favorise-les-discours-de-droite_6099540_4408996.html&quot;&gt;favorisées par les algorithmes de Twitter/X&lt;/a&gt; et les &lt;a href=&quot;https://www.lexpress.fr/monde/russie-doppelganger-la-vaste-operation-de-desinformation-de-moscou-pour-destabiliser-la-france-2G4K4U52PZDJ3IS6E6RABX4CRA/&quot;&gt;manipulations de la Russie déstabilisent nos démocraties&lt;/a&gt;.
Savoir que ce que je développe sert à l&amp;#8217;effondrement de la société et à la propagation des idées les plus nauséabondes me rend malade.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Force est de constater que le populisme monte en flèche : il a gagné au Brésil (Bolsonaro), aux Etats-Unis (Trump), au Royaume-Uni (Jonhson), en Hongrie (Orban), aux Pays-Bas (Wilders), en Argentine (Milei).
Il faut être sacrément optimiste pour croire que la France puisse miraculeusement échapper à ce fléau.
Pour autant, une fois en place, nous savons ce que ces gouvernements pensent de l&amp;#8217;économie et donc de l&amp;#8217;écologie.
Pire, nous savons ce que ces personnes pensent du droit des femmes et plus largement de toute personne ne pensant pas comme eux.
Je vous invite d&amp;#8217;ailleurs à écouter cette &lt;a href=&quot;https://www.youtube.com/watch?v=B2SI1zMN5ho&quot;&gt;interview de Véra Nikolski et Jancovici&lt;/a&gt; sur la fin de l&amp;#8217;ère du pétrole et ses conséquences sur la démocratie et le droit des femmes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les idées qui sont promues dans nos sociétés modernes sont incompatibles avec nos objectifs climatiques : nous devons tous travailler, devons être encore et toujours plus productifs.
Les outils que nous concevons, en informatique, font gagner de la productivité, mais cette productivité n&amp;#8217;est pas rendue au travailleur pour du temps libre, elle est réinvestie en plus de croissance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Produire, consommer, produire, consommer, produire&amp;#8230;&amp;#8203; &quot;pouvoir d&amp;#8217;achat&quot; et zéro chômage érigés en totems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce que je constate donc tous les jours est une fuite en avant, doublée d&amp;#8217;un déni, mais pire encore, une réaction exactement inverse à ce qu&amp;#8217;il faudrait faire pour maintenir notre consommation sous les &lt;a href=&quot;https://fr.wikipedia.org/wiki/Limites_plan%C3%A9taires&quot;&gt;limites planétaires&lt;/a&gt;.
Dès lors, la question de l&amp;#8217;effondrement civilisationnel se pose : si tant est que nous prenions le virage, qu&amp;#8217;en est-il des pays qui ne le feront pas et auront la capacité à nous menacer, précisément parce qu&amp;#8217;ils auront fait le choix inverse ?
C&amp;#8217;est un dilemme auquel je n&amp;#8217;ai pas de réponse, mais d&amp;#8217;autres questions ne sont pas agréables à entendre :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Que ferons-nous lorsque les populations qui ne pourront plus vivre dans leur pays frapperont à notre porte ?
Que ferons-nous lorsque nous ne pourrons plus importer nos médicaments, faute de moyens de transport longue distance ?
Que ferons-nous lorsque l&amp;#8217;Afrique nous demandera des comptes pour l&amp;#8217;exploitation de ses ressources ?
Que ferons-nous si nous n&amp;#8217;avons plus de pétrole pour faire rouler nos tanks, voler nos avions et nous défendre contre des pays en quête de conquêtes territoriale, économique ou culturelle ?
Que ferons-nous lorsque nous aurons tellement détruit nos services publics (transports, écoles, hôpitaux, production électrique) que nous serons dépendants de services commerciaux dont la seule survie ne dépend que de leurs marges ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La mondialisation nous a paradoxalement mis dans une situation extrêmement précaire, l&amp;#8217;Europe d&amp;#8217;aujourd&amp;#8217;hui est incroyablement fragile.
Tout ça au nom de la sacro-sainte croissance, un concept qui rappelons-le, n&amp;#8217;a aucun sens physique, c&amp;#8217;est une pure construction mathématique permettant d&amp;#8217;évaluer l&amp;#8217;activité économique d&amp;#8217;un pays.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Or, l&amp;#8217;activité économique ne se mesure pas qu&amp;#8217;à l&amp;#8217;aube de ce qui s&amp;#8217;achète.
C&amp;#8217;est pourtant ce que nous faisons tous les jours.
Ainsi, le comptable qui travaille bénévolement dans une association humanitaire fait le même travail que le comptable qui travaille dans une entreprise d&amp;#8217;extraction de minerais.
L&amp;#8217;un ne contribue pas au PIB, l&amp;#8217;autre oui.
Leurs contributions au bien-être de l&amp;#8217;humanité sont elles pour autant comparables ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Se passer de la croissance n&amp;#8217;est pas sans poser des problèmes, tant elle est au cœur de notre société.
Sans croissance, point de retraites, tout un monde de solidarité à réinventer !
Quelle entreprise accepterait &lt;em&gt;volontairement&lt;/em&gt; de ne pas croître, alors que cela menacerait directement sa survie face aux concurrents qui, eux, prendront la décision de continuer ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pourtant, décroître l&amp;#8217;industrie automobile, responsable d&amp;#8217;une grande partie du réchauffement, de morts sur la route, de la pollution aux particules fines, ne serait que bénéfique pour notre société.
Nous ne parlons pas de la supprimer du jour au lendemain, mais de &lt;em&gt;planifier notre sortie&lt;/em&gt;.
De même, l&amp;#8217;opulence de agro-industrie devra disparaître, c&amp;#8217;est une question de survie, au profit d&amp;#8217;une agriculture raisonnée : produisons moins, mais de meilleure qualité, avec des revenus décents et moins de transformations.
A court terme, achetons des &lt;a href=&quot;https://www.fairphone.com&quot;&gt;Fairphone&lt;/a&gt; plutôt que des &lt;a href=&quot;https://www.apple.com/apple-vision-pro/&quot;&gt;Vision Pro&lt;/a&gt;, achetons des produits réparables plutôt que des produits pas chers mais écologiquement aberrants.
Les leviers sont nombreux, il faut &quot;simplement&quot; une volonté politique.
Réapprenons à mutualiser, nous pouvons inventer de nouveaux modèles basés sur la coopération.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Plus nous attendons, moins les mesures que nous devrons prendre seront socialement acceptables et plus le risque de révolution sera important.
Il n&amp;#8217;est pas surprenant qu&amp;#8217;on utilise l&amp;#8217;expression d&amp;#8217;écologie punitive, dans ce contexte, alors que le plus punitif, ce sont les conséquences directes de la surexploitation de notre environnement : inondations, sécheresses, maladies, incendies, &amp;#8230;&amp;#8203;
La punition est vécue de plein fouet par les agriculteurs qui perdent leurs récoltes, des entrepreneurs qui voient leur camping partir en fumée, des habitants qui voient leur habitation détruite par des inondations ou des tornades&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En conclusion, tout semble converger vers l&amp;#8217;idée d&amp;#8217;un crash massif à venir : c&amp;#8217;est la combinaison du réchauffement climatique, de l&amp;#8217;effondrement de la biodiversité, du mythe de la croissance infinie, de la montée du populisme et de la raréfaction des ressources fossiles qui rend cet avenir possible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Jamais ne n&amp;#8217;aurais pensé, lorsque je discutais dans cette cour de récréation, voir cela de mon vivant.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Désormais, non seulement je le vois venir mais je le vois de plus en plus probable.
Je ne saurais quantifier, mais pour moi nous sommes sortis du domaine du possible pour entrer dans celui du probable.
Je n&amp;#8217;ai pas de solutions miracles, sans changement fondamental de notre mode de vie, mais j&amp;#8217;ai des questions, des craintes et aussi un message à faire passer : &lt;strong&gt;il est encore temps&lt;/strong&gt;.
La première de nos libertés, c&amp;#8217;est encore de voter, faisons le tant que nous en avons encore la possibilité.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Stacking and mosaic creation with JSol&amp;#8217;Ex 2.0</title>
      <link>https://melix.github.io/blog//2024/01-04-jsolex-2.0.html</link>
      <pubDate>Thu, 4 Jan 2024 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2024/01-04-jsolex-2.0.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A couple days ago I have released &lt;a href=&quot;https://github.com/melix/astro4j/releases/tag/2.0.0&quot;&gt;JSol&amp;#8217;Ex 2.0&lt;/a&gt;.
This software can be used as an alternative to &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;INTI&lt;/a&gt; to process solar images acquired using Christian Buil&amp;#8217;s &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-presentation-en.html&quot;&gt;Sol&amp;#8217;Ex&lt;/a&gt;.
This new version introduces 2 new features that I would like to describe in more details in this blog post: stacking and mosaic stitching.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_stacking&quot;&gt;Stacking&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Stacking should be something familiar to anyone doing planetary imaging.
One of the most popular sofware for doing stacking is &lt;a href=&quot;https://www.autostakkert.com/wp/&quot;&gt;AutoStakkert!&lt;/a&gt; which has recently seen a new major version.
Stacking usually consists of taking a large number of images, selecting a few reference points and trying to align these images to reconstruct a single, stacked image which increases the signal-to-noise ratio.
Each of the individual images are usually small and there are a large number of images (since the goal is to reduce the impact of turbulence, typically, videos are taken with a high frame rate, often higher than 100 frames per second).
In addition, there are little to no changes between the details of a series (granted that you limit the capture to a few seconds, to avoid the rotation of the planet typically) so the images are really &quot;only&quot; disformed by turbulence.
In the context of Sol&amp;#8217;Ex image processing, the situation is a bit different: we have a few captures of large images: in practice, capturing an image takes time (it&amp;#8217;s a scan of the sun which will consist of a video of several seconds just to build a &lt;em&gt;single&lt;/em&gt; image) and the solar details can move quickly between captures.
In practice, it means that you can reasonably stack 2 to 5 images, maybe more if the scans are quick enough and that there are not too many changes between scans.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The question for me was how to implement such an algorithm for JSol&amp;#8217;Ex?
Compared to planetary image stacking, we have a few advantages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;images have a great resolution: depending on the camera that you use and the binning mode, you can have images which range from several hundreds pixels large to a few thousands pixels&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the images are well defined : in planetary observation, there are a few &quot;high quality&quot; images in a video of several thousand frames, but most images are either fully or partially disformed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;there&amp;#8217;s little movement between images: anyone who has stacked a planetary video can see that it&amp;#8217;s frequent to see jumps of several pixels between 2 images, just because of turbulence&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;for each image, we already have determined the ellipse which makes the solar disk and should also have corrected the geometry, so that all solar disks are &quot;perfect circles&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, a naive approach, which I tried without success a few months ago, is a geometric approach where we simply make all solar disks the same (by resizing), align them then create an average image.
To illustrate this approach, let&amp;#8217;s look at some images:&lt;/p&gt;
&lt;/div&gt;
 &lt;video width=&quot;1024&quot; height=&quot;768&quot; controls&gt;
  &lt;source src=&quot;https://melix.github.io/blog/img/jsolex2/reference.webm&quot; type=&quot;video/webm&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this video we can see that there is quite some movement visible between each image.
Each of them is already of quite good quality, but we can notice some noise and more importantly, a shear effect due to the fact that a scan takes several seconds and that we reconstruct line by line :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/stack-ref.jpg&quot; alt=&quot;stack ref&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The average image is therefore quite blurry:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/stack-average.jpg&quot; alt=&quot;stack average&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, using the average image is &lt;em&gt;not&lt;/em&gt; a good option for stacking and that&amp;#8217;s why I recommended to use &lt;a href=&quot;https://www.autostakkert.com/wp/&quot;&gt;AutoStakkert!&lt;/a&gt; instead, which gave better results.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to achieve better results, I opted for a simple yet effective algorithm:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;first, estimate the sharpness of each image. This is done by computing the &lt;a href=&quot;https://en.wikipedia.org/wiki/Laplace_operator&quot;&gt;Laplacian&lt;/a&gt; of each image. The image with the best sharpness is selected as the &lt;em&gt;reference&lt;/em&gt; image&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;divide each image into tiles (by default, a tile has a width of 32 pixels)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;for each tile, try to align it with the reference image by computing an error between the reference tile and the image&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the error is based on root mean squared error of the pixel intensities : the better the tiles are aligned, the closer to 0 the error will be&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;this is the most expensive operation, because it requires computing the error for various positions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we&amp;#8217;re only looking for displacements with a maximum shift of 2/3 of the tile size (so, by default, 21 pixels maximum)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;if the shift between 2 tiles is higher than this limit, we won&amp;#8217;t be able to align the tiles properly&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We could have stopped here and already reconstruct an image at this stage, but the result wouldn&amp;#8217;t be great: the fact that we use tiles would be visible at the edges of the tiles, with square artifacts clearly visible.
To reduce the artifacts, I opted for a &quot;sliding window&quot; algorith, where the next tile will overlap the previous one by a factor between 0 (no overlap) and 1 (100% overlap).
This means that for each pixel, we will get a &quot;stack&quot; of pixel values computed from the alignment of several tiles.
The final pixel value is then computed by taking the median value of the stack.
Even so, some stacking vertical or horizontal artifacts can still be sometimes visible, so the last &quot;trick&quot; I used is to build the stacks by only taking pixels within a certain radius, instead of the whole square.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The resulting, stacked image is here:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/stack-jsolex.jpg&quot; alt=&quot;stack jsolex&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can see that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;noise from the original images is gone&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;shearing artifacts are significantly reduced&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the resulting image is not as blurry as the average version&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There were, however, some compromises I had to make, in order to avoid that the stacking process takes too long.
In particular, the tile alignment process (in particular error computation) is very expensive, since for each tile, we have to compute 21*21 = 441 errors by default.
With an overlap factor of 0.3, that&amp;#8217;s, for an image of 1024 pixels large, more than 5 million errors to compute.
Even computing them in parallel takes long, therefore I added &lt;a href=&quot;https://en.wikipedia.org/wiki/Local_search_(optimization)&quot;&gt;local search optimization&lt;/a&gt;: basically, instead of searching in the whole space, I&amp;#8217;m only looking for errors within a restricted radius (8 pixels).
Then, we take the minimal error of this area and resume searching from that position: step by step we&amp;#8217;re moving &quot;closer&quot; to a local optimum which will hopefully be the best possible error.
While this doesn&amp;#8217;t guarantee to find the best possible solution, it proved to provide very good results while significantly cutting down the computation times.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;From several tests I made, the quality of the stacked image matches that of Autostakkert!.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_mosaic_composition&quot;&gt;Mosaic composition&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next feature I added in JSol&amp;#8217;Ex 2, which is also the one which took me most time to implement, is mosaic composition.
To some extent, this feature is similar to stacking, except that in stacking, we know that all images represent the same region of the solar disk and that they are roughly aligned.
With mosaics, we have to work with different regions of the solar disk which overlap, and need to be stitched together in order to compose a larger image.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On December 7th, 2024, I had given a glimpse of that feature for &lt;a href=&quot;https://www.astro-images-processing.fr/articles/135166-pratique-et-traitement-d-images-sol-ex&quot;&gt;the french astrophotograhers association AIP&lt;/a&gt;, but I wasn&amp;#8217;t happy enough with the result so decided to delay the release.
Even today, I&amp;#8217;m not fully satisfied, but it gives reasonable results on several images I tried so decided it was good enough for public release and getting feedback about this feature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mosaic composition is not an easy task: there are several problems we have to solve:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;first, we need to identify, in each image, the regions which &quot;overlap&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;then for each image, we need to be able to tell if the pixel value we read at a particular place is relevant for the whole composition or not&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;then we have to do the alignment&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and finally avoid mosaicing artifacts, typically vertical or horizontal lines at the &quot;edges&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, mosaic composition is not immune to the problem that each image can have different illumination, or even that the regions which are overlapping have slightly (or even sometimes significantly) moved between the captures.
Therefore, the idea is to &quot;warp&quot; images together in order to make them stitch smoothly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_preparing_panels_for_integration&quot;&gt;Preparing panels for integration&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are the main steps of the algorithm I have implemented:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;resize images so that they all solar disks have the same radius (in pixels), and that all images are square&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;normalize the histograms of each panel so that all images have similar lightness&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;estimate the background level of each panel, in order to have a good estimate of when a pixel of an image is relevant or not and perform background neutralization&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;there can be more than 2 panels to integrate. My algorithm works by stitching them 2 by 2, which implies sorting the panels by putting the panels which overlap the most in front, then stitching the 2 most overlapping panels together. The result of the operation is then stitched together with the next panel, until we have integrated all of them.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The stitching part works quite differently than with typical stacking.
In stacking, we have &lt;em&gt;complete&lt;/em&gt; data for each image: we &quot;only&quot; have to align them.
With mosaics, there are &quot;missing&quot; parts in the image that we need to fill in.
To do this, we have to identify which part of a panel can be blended into the reconstructed image in order to complete it.
This means that the alignment process is significanly more complicated than with typical stacking, since we will work on &quot;missing&quot; data.
Part of the difficulty is precisely identifying if something is missing or not, that is to say if the signal of a pixel in one of the panels is relevant to the composition of the final image.
This is done by comparing it with the estimated background level, but that&amp;#8217;s not the only trick.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Despite the fact that our panels are supposedly aligned and that the circles representing the solar disks are supposed to be the same, in practice, depending on the quality of the capture and the ellipse regression success, the disks may be &lt;em&gt;slightly off&lt;/em&gt;, with deformations.
There can even be slight rotations between panels (because of flexions at capture time, or processing artifacts).
As a consequence, a naive approach consisting of trying to minimize the error between 2 panels by moving them a few pixels in each direction like in stacking &lt;em&gt;doesn&amp;#8217;t work&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;first of all, while you may properly align one edge of the solar disk, we can see that some regions will be misaligned. If these regions correspond to high contrast areas like filaments, it gives real bad results. If it happens at the edges of the sun, you can even see part of the disk being shifted a few pixels away from the other panel, which is clearly wrong.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;second, estimating the error is not so simple, since we have &lt;em&gt;incomplete&lt;/em&gt; disks. And in this case, the error has to be computed on large areas, which means that the operation is very expensive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;third, because we have to decide whether to pick a pixel from one panel or the other, this has the tendency to create very strong artifacts (vertical or horizontal lines) at the stitching edges&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_stitching_algorithm&quot;&gt;The stitching algorithm&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Giving all the issues I described above, I chose to implement an algorithm which would work similarly to stacking, by &quot;warping&quot; a panel into another.
This process is iterative, and the idea is to take a &quot;reference&quot; panel, which is the one which has the most &quot;relevant&quot; pixels, and align tiles from the 2d panel into this reference panel.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To do this, we compute a grid of &quot;reference points&quot; which are in the &quot;overlapping&quot; area.
These points belong to the reference image, and one difficulty is to filter out points which belong to &quot;incomplete&quot; tiles.
Once we have these points, for each of them, we compute an alignment between the reference tile and the tile of the panel we&amp;#8217;re trying to integrate.
This gives us, roughly, a &quot;model&quot; of how tiles are displaced in the overlapping area.
The larger the overlapping area is, the better the model will be, but experience shows that distorsion on one edge of the solar disk can be significanly different at the other edge.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next step consists of trying to align tiles of the panel we integrate to the reference panel using this model.
This is where the iteration process happens.
In a nutshell, we have an area where the solar disk is &quot;truncated&quot;.
Even if we split the image in tiles like with stacking, we cannot really tell whether a tile is &quot;complete&quot; or not, because it depends both on the pixel intensities of the reference panel and the second panel, and the background level.
In particular, calcium images may have dark areas &lt;em&gt;within&lt;/em&gt; the solar disk which are sometimes as dark as the background.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are struggling to understand how difficult it can be to determine if part of the image we consider is relevant or not, let&amp;#8217;s illustrate with this image:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/panel_noise.jpg&quot; alt=&quot;panel noise&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can you see what&amp;#8217;s wrong in this image?
Let&amp;#8217;s increase constrast to make it clearly visible:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/panel_noise2.jpg&quot; alt=&quot;panel noise2&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now it should be pretty obvious that below the south edge of the truncated disk, we have an area which has pixels which are above the value of the background, but do not constitute actual signal!
This problem took me quite some time to solve, and it&amp;#8217;s only recently that I figured out a solution: before mosaicing, I am performing a background neutralization step, by modeling the background and substracting it from the image.
While this doesn&amp;#8217;t fully solve the problem, it makes it much less relevant for composition.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, we have to compose the image using tiles which are incomplete, and we don&amp;#8217;t know the orientation of the panels: they can be assembled north/south, or west/east, and nothing tells us.
Potentially, it can even be a combination of these for a large number of panels.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, the algorithm works by creating a &quot;mask&quot; of the image being reconstructed.
This mask tells us &quot;for this particular pixel, I have reconstructed a value, or the value of the reference image is good enough and we won&amp;#8217;t touch it&quot;.
Then, for each tile, we consider tiles for which the mask is incomplete.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to determine how to align the truncated disk with data from the other image, we compute an estimate of the distortion of the tile based on the displacements models we have determined earlier.
Basically, for a new &quot;tile&quot; to be integrated, we will consider the sample &quot;reference points&quot; which are within a reasonable distance of the tile.
For this set of reference points, we know that they are &quot;close enough&quot; to compute an average model of the distorsion, that I call the &quot;local distorsion&quot;: we can estimate, based on the distance of each reference point, how much they contribute to the final distorsion model for that particular point.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The key is really to consider &lt;em&gt;enough&lt;/em&gt; samples to have a good distorsion model, but not too many because then the &quot;locality&quot; of alignment would become too problematic and we&amp;#8217;d face misalignments.
Because there are not so many samples for each &quot;incomplete&quot; tile, we are in fact going to reconstruct, naturally, the image from the edges where there&amp;#8217;s missing data: when there are no samples, it basically means we cannot compute a model, so we don&amp;#8217;t know how to align tiles.
If we have enough samples, then we can compute a reliable model of the distorsion, and then we can reconstruct the missing part of each tile, by properly aligning the tiles together.
If the number of samples is not sufficient to consider a good model, then we assume that no distorsion happens, which is often the case for &quot;background&quot; tiles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Most of the difficulty in this algorithm is properly identifying &quot;when&quot; we can stitch tiles together, that is to say when we can tell that the alignment between tiles makes sense and that the alignment is correct.
Often, I got good results for one kind of images (e.g, h-alpha images) but horrible results with others (e.g calcium) or the other way around.
I cannot really say I took a very scientific approach to this problem, but more an empirical approach, tweaking parameters of my algorithm until it gave good enough results in all cases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I mentioned that the algorithm is iterative, but didn&amp;#8217;t explain why yet: when we compute the tile alignments, we only do so because we have enough local samples for alignment.
We do this for all tiles that match this criteria, but we won&amp;#8217;t, for example, be able to align a tile which is in the top of the image, if the bottom hasn&amp;#8217;t been reconstructed.
Therefore, the iteration happens when we have reconstructed all the tiles we could in one step: then we recompute new reference points, and complete the image, not forgetting, of course, to update our mask to tell that some pixels were completed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Overall the algorithm is fairly fast, and can be stopped once we have completed all tiles, or after a number of fixed iterations in case of difficulties (often due to the background itself).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_one_last_step&quot;&gt;One last step&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The algorithm we&amp;#8217;ve described provides us with a way to &quot;roughly&quot; reconstruct an image, but it doesn&amp;#8217;t work like what you&amp;#8217;d intuititvely think of mosaic composition, by &quot;moving&quot; 2 panels until they properly align and blend them toghether.
Instead, it will reconstruct an image by assembling &lt;em&gt;tiles&lt;/em&gt; together, from what is &lt;em&gt;already&lt;/em&gt; reconstructed: it is more fine grained, which will fix a number of the issues we&amp;#8217;ve faced before: local distorsions, or images which are not properly aligned because the details at the surface at the sun &lt;em&gt;have moved&lt;/em&gt; between the moment the first panel was captured and the second one did.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If we stopped there, we would see an image which looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/mosaic_reconstructed.jpg&quot; alt=&quot;mosaic reconstructed&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can see a clear horizontal line, which is due to the fact that we&amp;#8217;re reconstructing using tiles, and that depending on the alignment of tiles with the &quot;missing&quot; areas, we can have strong or weak artifacts at the borders.
Errors are even more visible in this image in calcium K line:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/mosaic_error_calcium.jpg&quot; alt=&quot;mosaic error calcium&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This time it&amp;#8217;s very problematic and we are facing several of the issues we attempted to avoid: details have significantly moved between the north and south panel were captured, which leads to &quot;shadowing&quot; artifacts, and there are also tiling artifacts visible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, the image we get is &lt;em&gt;good enough&lt;/em&gt; to perform one last step: use it as a &lt;em&gt;reference image&lt;/em&gt; in the stacking algorithm we described in the first section of this blog post.
The reason stacking works well is because we know we have complete images that we can align.
Here, we have roughly reconstructed an image that we can use as a &quot;complete reference&quot;.
The idea is therefore to take each tile of each panel and &quot;blend&quot; it using the reconstructed reference.
Of course, there is one big difference between the stacking in the first section and the stacking we have to do now.
We&amp;#8217;re not really going to use the reconstructed image, except for aligning tiles together and computing a &quot;weight&quot; for each tile, which depends on the relative luminosity between the reference image tile we&amp;#8217;re considering and the corresponding panel tile.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This gives us a pretty good result:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/mosaic_halpha_final.jpg&quot; alt=&quot;mosaic halpha final&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/jsolex2/mosaic_calcium_final.jpg&quot; alt=&quot;mosaic calcium final&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The images we got there are not perfect, which is why I&amp;#8217;m not fully satisfied yet, but they are however already quite good, given that it&amp;#8217;s all done in a few seconds, using the same software that you&amp;#8217;d use to reconstruct Sol&amp;#8217;Ex images!
In other words, the goal of these features is &lt;em&gt;not&lt;/em&gt; to get the same level of quality that you&amp;#8217;d get by using your favorite post-processing or mosaic composition software, but good enough to get you a reasonable result in a reasonable amount of time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, on my machine, it takes less than one minute to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;stack images of the north and south panels (~10 images to stack)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;stitch them together in a mosaic&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It would have taken several minutes, or even more, using external software, especially for the mosaic part.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, I have described how I got to implement 2 algorithms, the stacking algorithm and the mosaic composition one, in JSol&amp;#8217;Ex.
None of the algorithms were based on any research paper: they were really designed in an &quot;adhoc&quot; way, as my intuition of how things could work.
It proved to be quite difficult, and it is very likely that better algorithms are described in the wild: I will consider them for future versions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nevertheless, I&amp;#8217;m quite happy with the outcome, since, remember, I have started this program as an experiment and for learning purposes only.
Now I sincerely hope that it will help you get amazing solar images!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Introducing astro4j</title>
      <link>https://melix.github.io/blog//2023/04-22-introducing-astro4j.html</link>
      <pubDate>Sat, 22 Apr 2023 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2023/04-22-introducing-astro4j.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This blog introduces &lt;a href=&quot;https://github.com/melix/astro4j&quot;&gt;astro4j&lt;/a&gt;, my latest toy project, a open source collection of libraries and applications for astronomy, written in Java.
In particular, I will discuss &lt;a href=&quot;https://github.com/melix/astro4j/tree/main/jsolex&quot;&gt;JSol&amp;#8217;Ex&lt;/a&gt;, a program aimed at reconstructing solar disk images from video files captured using the amazing &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-presentation-en.html&quot;&gt;Sol&amp;#8217;Ex&lt;/a&gt; instrument.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_why_astro4j&quot;&gt;Why astro4j?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m a software developer, and if you are following me, you may also know that I&amp;#8217;m an &lt;a href=&quot;https://www.astrobin.com/users/melix/&quot;&gt;amateur astrophotographer&lt;/a&gt;.
For a long time, I&amp;#8217;ve been fascinated by the quality of software we have in astronomy, to process images.
If you are french speaking, you can watch a &lt;a href=&quot;https://www.youtube.com/watch?v=tSgnOtdjVHs&quot;&gt;presentation I gave about this topic&lt;/a&gt;.
Naturally, I have been curious about how all these things work, but it&amp;#8217;s actually extremely rare to find open source software, and when you do, it&amp;#8217;s rarely written in Java.
For example, both &lt;a href=&quot;http://www.firecapture.de/&quot;&gt;Firecapture&lt;/a&gt; (software to capture video streams) and &lt;a href=&quot;https://www.astropixelprocessor.com/&quot;&gt;Astro Pixel Processor&lt;/a&gt; are written in Java, but both of them are closed source, commercial software.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last month, for my birthday, I got a &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-presentation-en.html&quot;&gt;Sol&amp;#8217;Ex&lt;/a&gt;, an instrument which combines spectrography and software to realize amazing solar pictures in different spectral lines.
To process those images, the easiest solution is to use &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;the amazing INTI software&lt;/a&gt;, written in Python, but for which sources are not published, as far as I know, neither on GitHub or GitLab.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
After announcing this project, I have been notified that the sources of INTI &lt;a href=&quot;https://github.com/Vdesnoux/Solex_ser_recon&quot;&gt;are indeed available, as GPL&lt;/a&gt;. It&amp;#8217;s a pity they are not linked on the webpage, this would have helped a lot.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To give you an example of what you can do, here&amp;#8217;s the &lt;a href=&quot;https://www.astrobin.com/94gymd/&quot;&gt;first photography&lt;/a&gt; I&amp;#8217;ve done with Sol&amp;#8217;Ex and processed with INTI (color was added in Gimp):&lt;/p&gt;
&lt;/div&gt;
&lt;a href=&quot;https://astrob.in/94gymd/0/&quot;&gt;&lt;img src=&quot;https://astrob.in/94gymd/0/rawthumb/regular/get.jpg?insecure&quot;/&gt;&lt;/a&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To get this result, one has to combine images which look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/spectrum.png&quot; alt=&quot;spectrum&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Interesting, no?
At the same time, I was a bit frustrated by INTI.
While it clearly does the job and is extremely easy to use, there are a few things which I didn&amp;#8217;t like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the first, which I mentioned, is that it&amp;#8217;s using Python and that the sources are not published (as far as I understand, some algorithms are not published yet). I am not surprised that Python is used, because it&amp;#8217;s a language which is extremely popular in academics, with lots of libraries for image processing, science oriented libs, etc. However, because it&amp;#8217;s popular in academics also means that programs are often written by and for academics. When we&amp;#8217;re talking about maths, it&amp;#8217;s often short variable names, cryptic function names, etc&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;second, after processing, INTI pops up a lot of images as individual windows. If you want to process a new file, you have to close all of them. The problem is that I still haven&amp;#8217;t figured out in which order you have to do this so that you can restart from the initial window which lets you select a video file! Apparently, depending on the order, it will, or will not, show the selector. And sometimes, it takes several seconds before it does so.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;INTI seems to be regenerating a font cache every time I reboot. This operation takes several minutes. It&amp;#8217;s probably an artifact of packaging the application for Windows, but still, not very user friendly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;INTI generates a number of images, but puts them alongside the videos. I like things organized (well, at least virtually, because if you looked at my desk right now, it is likely you&amp;#8217;d feel faint), so I wish it was creating one directory per processed video.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/inti-popups.png&quot; alt=&quot;inti popups&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_confronting_the_old_demons&quot;&gt;Confronting the old demons&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I started studying at University, back in 1998, I was planning to do astrophysics.
However, I quickly forgot about this idea when I saw the amount of maths one has to master to do modern physics.
Clearly, I was reaching my limits, and it was extremely complicated for me.
Fortunately, I had been doing software development for years already, because I started very young, on my father&amp;#8217;s computer.
So I decided to switch to computer science, where I was reasonably successful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, not being able to do what I wanted to do has always been a frustration. It is still, today, to the point that a lot of what I&amp;#8217;m reading is about this topic, but still, I lack the maths.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was time for me to confront my old demons, and answer a few questions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;am I still capable of understanding maths, in order to implement algorithms which I use everyday when I do astronomy image processing with software written by others?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can I read academic papers, for example to implement a FFT (Fast Fourier Transform) algorithm, although I clearly remember that I failed to understand the principles when I was at school?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;can I do this while writing something which could be useful to others, and publish it as open source software?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Astro4j is there to answer those questions.
I don&amp;#8217;t have the answers yet and time will tell if I&amp;#8217;m successful.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_using_modern_java&quot;&gt;Using modern Java&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One question you may have is why Java? If you are not familiar with this language, you may have this old misconception that Java is slow.
It&amp;#8217;s not. Especially, if you compare to Python, it&amp;#8217;s definitely not.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This project is also for me a way to prove that you can implement &quot;serious science&quot; in Java.
You can already find some science libraries in Java, but they tend to me impractical to use, because not following the industry standards (e.g published on Maven Central) or platform-dependent.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I also wanted to leverage this to &lt;em&gt;learn something new&lt;/em&gt;.
So this project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;uses Java 17 (at least for libraries, so that they can be consumed by a larger number of developers, for applications I&amp;#8217;m considering moving to Java 20)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;uses &lt;a href=&quot;https://openjfx.io/&quot;&gt;JavaFX&lt;/a&gt; (OpenJFX) for the application UI&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;experiments with the &lt;a href=&quot;https://openjdk.org/jeps/438&quot;&gt;Vector API&lt;/a&gt; for faster processing&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As I said, my initial goal is to obtain a software which can basically do what INTI does.
It is not a goal to make it faster, but if I can do it, I will.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introducing_jsolex&quot;&gt;Introducing JSol&amp;#8217;Ex&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After a few evenings (and a couple week-ends ;)), I already have something which performs &lt;em&gt;basic processing&lt;/em&gt;, that is to say that it can process a SER video file and generate a reconstructed solar disk.
It does &lt;strong&gt;not&lt;/strong&gt; perform geometry correction, nor tilt correction, like INTI does. It doesn&amp;#8217;t generate shifted images either (for example the doppler images), but &lt;strong&gt;it works&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since the only source of information I had to do this was &lt;a href=&quot;http://www.astrosurf.com/solex/sol-ex-presentation-en.html&quot;&gt;Christian Buil&amp;#8217;s website&lt;/a&gt; and &lt;a href=&quot;http://valerie.desnoux.free.fr/inti/&quot;&gt;Valérie Desnoux INTI&amp;#8217;s website&lt;/a&gt;, I basically had to implement my own algorithms from A to Z, and just &quot;guess&quot; how it works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to do this, I had to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;implement a SER video file decoder. The library is &lt;a href=&quot;https://github.com/melix/astro4j/tree/main/jserfile&quot;&gt;ready&lt;/a&gt; and performs both decoding the SER file and performs demosaicing of images&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;on top of the decoder, I implemented a &lt;a href=&quot;https://github.com/melix/astro4j/tree/main/ser-player&quot;&gt;SER file player&lt;/a&gt;, which is still very basic at this stage, and uses JavaFX. This player can even be compiled to a native binary using &lt;a href=&quot;https://www.graalvm.org/&quot;&gt;GraalVM&lt;/a&gt;!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;
&lt;/div&gt;
 &lt;video width=&quot;800&quot; height=&quot;480&quot; controls&gt;
  &lt;source src=&quot;https://melix.github.io/blog/img/astro/solex/serplayer.webm&quot; type=&quot;video/webm&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then I could finally start working on the Sol&amp;#8217;Ex video processor.
As I said, I don&amp;#8217;t know how INTI works, so this is all trial and error, in the end&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the beginning, as I said, you have a SER video file which contains a lot of frames (for example, in my case, it&amp;#8217;s a file from 500MB to 1GB) that we have to process in order to generate a solar disk.
Each frame consists of a view of the light spectrum, centered on a particular spectral line.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, in the following image, we have the H-alpha spectral line:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/spectrum.png&quot; alt=&quot;spectrum&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because of optics, you can see that the line is not horizontal: each frame is distorted.
Therefore, in order to reconstruct an image, we have to deal with that distortion first.
For this, we have to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;detect the spectral line in the frame, which I&amp;#8217;m doing by implementing a simple contrast detection&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;perform a linear regression in order to compute a 2d order polynomial which models the distortion&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that before doing this, I had no idea how to do a 2d order regression, but I searched and found that it was possible to do so using the least squares method, so I did so.
The result is that we can identify precisely the line with this technique:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/spectrum-line.png&quot; alt=&quot;spectrum line&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the beginning, I tought I would have to perform distortion correction in order to reconstruct the image, because I was (wrongly) assuming that, because each frame represents &lt;em&gt;one&lt;/em&gt; line in the reconstructed image, I had to compute the average of the colums of each frame to determine the color of a &lt;em&gt;single&lt;/em&gt; pixel in the output. I was wrong (we&amp;#8217;ll come to that later), but I did implement a distortion correction algorithm:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/spectrum-corrected.png&quot; alt=&quot;spectrum corrected&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I computed the average, the resulting image was far from the quality and constrast of what I got with INTI.
What a failure!
So I thought that maybe I had to compute the average of the spectral line itself.
I tried this, and indeed, the resulting image was much better, but still not the quality of INTI.
The last thing I did, therefore, was to pick the middle of the spectral line itself, and then, magically, I got the same level of quality as with INTI (for the raw images, as I said I didn&amp;#8217;t implement any geometry or tilt correction yet).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The reason I was assuming that I had to compute an average, is that it wasn&amp;#8217;t clear to me that the &lt;em&gt;absorption ray&lt;/em&gt; would actually contain enough data to reconstruct an image.
As it was an absorption ray, I assumed that the value would be 0, and therefore that nothing would come out of using the ray itself.
In fact, my physics were wrong, and you &lt;em&gt;must&lt;/em&gt; use that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A direct consequence is that there is actually no need to perform a distortion correction.
Instead, you can just use the 2d order polynomial that we&amp;#8217;ve computed, and &quot;follow the line&quot;, that&amp;#8217;s it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, we can generate an image, but it will be very dark.
The reason is obvious: by taking the middle of the spectral line, we&amp;#8217;re basically using dark pixels, so the dynamics of the image are extremely low.
So, in order to have something which &quot;looks nice&quot;, you actually have to perform brightness correction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first algorithm I have used is simply a linear correction: we&amp;#8217;re computing the max and min value of the image, then rescaling that so that the max value is the maximum representable (255).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here&amp;#8217;s the result:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/linear.png&quot; alt=&quot;linear&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, I felt that this technique wouldn&amp;#8217;t give the best results, in particular because linear images tend to give results which are not what the eye would see: our eye performs a bit like an &quot;exponential&quot; accumulator, the more photos you get, the &quot;brighter&quot; we&amp;#8217;ll see it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I implemented another algorithm which I had seen in &lt;a href=&quot;https://pixinsight.com/&quot;&gt;PixInsight&lt;/a&gt;, which is called inverse hyperbolic (Arcsinh) correction:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/streched.png&quot; alt=&quot;streched&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last, you can see that the image has lots of vertical line artifacts.
This is due to the presence of dust either on the optics or the sensors.
INTI performs correction of those lines, and I wanted to do something similar.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again, I don&amp;#8217;t know what INTI is doing, so I figured out my own technique, which is using &quot;multipass&quot; correction.
In a nutshell, for each row, I am computing the average value of the row.
Then, for a particular row, I compute the average of the averages of the surrounding lines (for example, 16 rows before and after).
If the average of this line is &lt;em&gt;below&lt;/em&gt; the average of the averages(!), then I&amp;#8217;m considering that the line is darker than it should be, computing a correction factor and applying it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The result is a corrected image:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/solex/banding.png&quot; alt=&quot;banding&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We&amp;#8217;re still not a the level of quality that INTI produces, but getting close!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So what&amp;#8217;s next? I already have &lt;a href=&quot;https://github.com/melix/astro4j/issues&quot;&gt;added some issues for things I want to fix&lt;/a&gt;, and in particular, I&amp;#8217;m looking at improving the banding reduction and performing geometry correction.
For both, I &lt;em&gt;think&lt;/em&gt; I will need to use fast fourier transforms, in order to identify the noise in one case (banding) and detect edges in the other (geometry correction).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, I started to implement FFT transforms, a domain I had absolutely no knowledge of.
Luckily, I could ask &lt;a href=&quot;https://chat.openai.com/&quot;&gt;ChatGPT&lt;/a&gt; to explain to me the concepts, which made it faster to implement!
For now, I have only implemented the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm&quot;&gt;Cooley-Tukey&lt;/a&gt; algorithm.
The issue is that this algorithm is quite slow, and requires that the input data has a length which is a power of 2.
Given the size of the image we generate, it&amp;#8217;s quite costly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I took advantage of this to learn about the &lt;a href=&quot;https://openjdk.org/jeps/438&quot;&gt;Vector API&lt;/a&gt; to leverage SIMD instructions of modern CPUs, and it indeed made things significantly faster (about twice as fast), but still not at the level of performance that I expect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am trying to understand the &lt;a href=&quot;https://en.wikipedia.org/wiki/Split-radix_FFT_algorithm&quot;&gt;split radix&lt;/a&gt; but I&amp;#8217;m clearly intimidated by the many equations here&amp;#8230;&amp;#8203; In any case I printed some papers which I hope I&amp;#8217;ll be able to understand.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In conclusion, in this article, I&amp;#8217;ve introduced &lt;a href=&quot;https://github.com/melix/astro4j&quot;&gt;astro4j&lt;/a&gt;, an open source suite of libraries and applications written in Java for astronomy software.
While the primary goal for me is to learn and improve my skills and knowledge of the maths behind astronomy software processing, it &lt;em&gt;may&lt;/em&gt; be that it produces something useful.
In any case, since it&amp;#8217;s open source, if you want to contribute, feel free!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And you can do so in different domains, for example, I pretty much s* at UI, so if you are a JavaFX expert, I would appreciate your pull requests!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finally, here is a video showing JSol&amp;#8217;Ex in action:&lt;/p&gt;
&lt;/div&gt;
 &lt;video width=&quot;1024&quot; height=&quot;768&quot; controls&gt;
  &lt;source src=&quot;https://melix.github.io/blog/img/astro/solex/jsolex.webm&quot; type=&quot;video/webm&quot;&gt;
Your browser does not support the video tag.
&lt;/video&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>How the Micronaut team leverages Gradle&amp;#8217;s version catalogs for improved developer productivity</title>
      <link>https://melix.github.io/blog//2023/03-12-micronaut-catalogs.html</link>
      <pubDate>Sun, 12 Mar 2023 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2023/03-12-micronaut-catalogs.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This blog post discusses how the Micronaut development team makes use of a feature of Gradle, &lt;a href=&quot;https://docs.gradle.org/current/userguide/platforms.html&quot;&gt;version catalogs&lt;/a&gt;, to improve the team&amp;#8217;s developer productivity, reduce the risks of publishing broken releases, coordinate the releases of a large number of modules and, last but not least, provide additional features to our Gradle users.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_backstory&quot;&gt;The backstory&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://micronaut.io/&quot;&gt;Micronaut Framework&lt;/a&gt; is a modern open-source framework for building JVM applications.
It can be used to build all kinds of applications, from CLI applications to microservices or even good old monoliths.
It supports deploying both to the JVM and native executables (using &lt;a href=&quot;https://graalvm.org&quot;&gt;GraalVM&lt;/a&gt;), making it particularly suitable for all kind of environments.
A key feature of the Micronaut framework is developer productivity: we do everything we can to make things faster for developers.
In particular, Micronaut has a strong emphasis on easing how you test your applications, even in native mode.
For this we have built a number of tools, including our &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-maven-plugin/latest/&quot;&gt;Maven&lt;/a&gt; and &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-gradle-plugin/latest/&quot;&gt;Gradle&lt;/a&gt; plugins.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I joined the Micronaut team almost a couple years back, I was given the responsibility of improving the team&amp;#8217;s own developer productivity.
It was an exciting assignment, not only because I knew the team&amp;#8217;s love about Gradle, but because I also knew that there were many things we could do to reduce the feedback time, to provide more insights about failures, to detect flaky tests, etc.
As part of this work we have put in place a partnership with &lt;a href=&quot;https://gradle.com&quot;&gt;Gradle Inc&lt;/a&gt; which kindly provides us with a &lt;a href=&quot;https://ge.micronaut.io&quot;&gt;Gradle Enterprise instance&lt;/a&gt;, but this is not what I want to talk about today.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lately I was listening to an &lt;a href=&quot;https://www.youtube.com/watch?v=Gr96IxKwPeE&quot;&gt;interview of Aurimas Liutikas&lt;/a&gt; of the AndroidX team, who was saying that he didn&amp;#8217;t think that version catalogs were a good solution for library authors to share their recommendations of versions, and that BOMs are probably a better solution for this.
I pinged him saying that I disagreed with this statement and offered to provide more details why, if he was interested.
This is therefore a long answer, but one which will be easier to find than a &lt;a href=&quot;https://androiddev.social/@Aurimas/110000457198553518&quot;&gt;thread on social media&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_what_are_version_catalogs&quot;&gt;What are version catalogs?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s start with the basics: a version catalog is, like the name implies, a catalog of versions to pick from, nothing more.
That doesn&amp;#8217;t sound too much exciting, and what versions are we talking about?
That&amp;#8217;s version of &lt;em&gt;libraries&lt;/em&gt; or &lt;em&gt;plugins&lt;/em&gt; that you use in your build.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an illustration, here is a version catalog, defined as a TOML file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
javapoet = &quot;1.13.0&quot;

[libraries]
javapoet = { module = &quot;com.squareup:javapoet&quot;, version.ref = &quot;javapoet&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then this library &lt;em&gt;can&lt;/em&gt; be used in a &lt;code&gt;dependencies&lt;/code&gt; declaration block in any of the project&amp;#8217;s build script using a &lt;em&gt;type-safe notation&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation(libs.javapoet) {
        because(&quot;required for Java source code generation&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which is &lt;em&gt;strictly equivalent&lt;/em&gt; to writing:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation(&quot;com.squareup:javapoet:1.13.0&quot;) {
        because(&quot;required for Java source code generation&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are many advantages of using version catalogs to declare your library versions, but most notably it provides a single, standard location where those versions are declared.
It is important to understand that a catalog is simply a &lt;em&gt;list of dependencies you can pick from&lt;/em&gt;, a bit like going to the supermarket and choosing whatever you need for your particular meal: it&amp;#8217;s not because a catalog declares libraries that you &lt;em&gt;have to&lt;/em&gt; use them.
However, a catalog provides you with &lt;em&gt;recommendations&lt;/em&gt; of libraries to pick from.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_version_catalogs_for_micronaut_users&quot;&gt;Version catalogs for Micronaut users&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;An interesting aspect of version catalogs is that they can be published, for others to consume: they are an artifact.
Micronaut users can already make use of catalogs, as I have explained in a &lt;a href=&quot;https://melix.github.io/blog/2022/02/micronaut-version-catalog.html&quot;&gt;previous blog post&lt;/a&gt;.
This makes it possible for a user who doesn&amp;#8217;t know which version of Micronaut Data to use, to simply declare:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation mn.micronaut.data
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;People familiar with Maven BOMs can easily think that it is the same feature, but there are &lt;a href=&quot;https://docs.gradle.org/current/userguide/platforms.html#sub:platforms-vs-catalog&quot;&gt;key differences which are described in the Gradle docs&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the rest of this post we will now focus on how we generate those catalogs, and how they effectively help us in improving our own developer productivity.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_the_micronaut_team_uses_version_catalogs&quot;&gt;How the Micronaut team uses version catalogs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_one_catalog_per_module&quot;&gt;One catalog per module&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As I said, the Micronaut framework consists of a large number of modules which live in their own Git repository.
All the projects share the same layout, the same conventions in order to make things easier to maintain.
For this purpose, we use our own collection of &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-build&quot;&gt;internal build plugins&lt;/a&gt; as well as a &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-project-template&quot;&gt;project template&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those build plugins provide features like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;defining the default Java language level, setting up code conventions and code quality plugins&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;standardizing how documentation is built (using Asciidoctor)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;setting up integration with Gradle Enterprise, to publish build scans, configure the build cache and predictive test selection&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;implementing binary compatibility checks between releases&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;configuring publication to Maven Central&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;providing a high-level model of what a Micronaut module is&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last item is particularly important: in every Micronaut project, we have different kind of modules: libraries (which are published to Maven Central for users to consume), internal support libraries (which are not intended for external consumption), or a BOM module (which also publishes a version catalog as we&amp;#8217;re going to see).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Long story short: &lt;strong&gt;we heavily rely on conventions to reduce the maintenance costs, have consistent builds, with improved performance and higher quality standards&lt;/strong&gt;.
If you are interested in why we have such plugins, Sergio Delamo and I gave an &lt;a href=&quot;https://www.youtube.com/watch?v=fpz63IwFIZM&quot;&gt;interview about this&lt;/a&gt; a few months ago (alert: the thumbnail shows I have hair, this is fake news!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each of our projects declares a version catalog, for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;this &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-core/blob/4.0.x/gradle/libs.versions.toml&quot;&gt;one for Micronaut core&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;this &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-test-resources/blob/master/gradle/libs.versions.toml&quot;&gt;one for Micronaut Test Resources&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;this &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-kafka/blob/master/gradle/libs.versions.toml&quot;&gt;one for Micronaut Kafka&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;or this &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-gradle-plugin/blob/master/gradle/libs.versions.toml&quot;&gt;one for the Micronaut Gradle Plugin&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_automatic_version_upgrades&quot;&gt;Automatic version upgrades&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the advantages of version catalogs is that it provides a centralized place for versions, which can be easily used by bots to provide pull requests for dependency upgrades.
For this, we use &lt;a href=&quot;https://docs.renovatebot.com&quot;&gt;Renovatebot&lt;/a&gt; which integrates particularly well with version catalogs (GitHub&amp;#8217;s dependabot lacks behind in terms of support).
This allows us to get pull requests like &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-kafka/pull/660/files&quot;&gt;this one&lt;/a&gt; which are very easy to review.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_bom_and_version_catalog_generation&quot;&gt;BOM and version catalog generation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each of the Micronaut projects is now required to provide a BOM (Bill of Materials) for users.
Another term for a BOM that is used in the Gradle ecosystem is a &lt;em&gt;platform&lt;/em&gt;: a platform has however slightly different semantics in Maven and Gradle.
The main goal of a BOM is to provide a list of dependencies a project works with, and, in Maven, it &lt;em&gt;can&lt;/em&gt; be used to override the dependency versions of transitive dependencies.
While in Maven, a BOM will only influence the dependency resolution of the project which &lt;em&gt;imports&lt;/em&gt; the BOM, in Gradle a platform fully participates in dependency resolution, including when a transitive dependency depends on a a BOM.
To simplify, a user who &lt;em&gt;imports&lt;/em&gt; a BOM may use dependencies declared in the BOM &lt;em&gt;without specifying a version&lt;/em&gt;: the version will be fetched from the BOM.
In that regards, it looks exactly the same as a version catalog, but there are subtle differences.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, if a user imports a BOM, any transitive dependency matching a dependency found in the BOM will be overridden (Maven) or participate in conflict resolution (Gradle).
That is &lt;em&gt;not&lt;/em&gt; the case for a catalog: it will &lt;em&gt;not&lt;/em&gt; influence the dependency resolution unless you explicitly add a dependency which belongs to the catalog.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s why Micronaut publishes &lt;em&gt;both&lt;/em&gt; a BOM and a catalog, because they address different use cases, and they work particularly well when combined together.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Micronaut modules, you will systematically find a project with the &lt;code&gt;-bom&lt;/code&gt; suffix.
For example, Micronaut Security will have subprojects like &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-security/tree/master/security-jwt&quot;&gt;&lt;code&gt;micronaut-security-jwt&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-security/tree/master/security-oauth2&quot;&gt;&lt;code&gt;micronaut-security-oauth2&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-security/tree/master/security-bom&quot;&gt;&lt;code&gt;micronaut-security-bom&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The BOM project will aggregate dependencies used by the different modules.
In order to publish a BOM file, the only thing a project has to do is to apply our convention plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;plugins {
    id &quot;io.micronaut.build.internal.bom&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note how we don&amp;#8217;t have to declare the coordinates of the BOM (group, artifact, version), nor that we have to declare how to publish to Maven Central, what dependencies should be included in the BOM, etc: &lt;em&gt;everything&lt;/em&gt; is done by convention, that&amp;#8217;s the magic of &lt;a href=&quot;https://melix.github.io/blog/2021/12/composition-in-gradle.html&quot;&gt;composition over inheritance&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Should we want to change how we generate the BOM, the only thing we would have to do is to update our internal convention plugin, then all projects would benefit from the change once they upgrade.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_convention_over_configuration&quot;&gt;Convention over configuration&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to determine which dependencies should be included in our BOM, we defined &lt;em&gt;conventions&lt;/em&gt; that we use in our catalog files.
In our internal terminology, when we want a dependency to be handled by the Micronaut framework, we call that a &lt;em&gt;managed&lt;/em&gt; dependency: a dependency that is managed by Micronaut and that users shouldn&amp;#8217;t care about in most cases: they don&amp;#8217;t have to think about a version, we will provide one for them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This directly translates to a convention in the version catalogs of the Micronaut projects: dependencies which are &lt;em&gt;managed&lt;/em&gt; need to be declared with a &lt;code&gt;managed-&lt;/code&gt; prefix in the catalog:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
...
managed-kafka = &apos;3.4.0&apos;
...
zipkin-brave-kafka-clients = &apos;5.15.0&apos;

[libraries]
...
managed-kafka-clients = { module = &apos;org.apache.kafka:kafka-clients&apos;, version.ref = &apos;managed-kafka&apos; }
managed-kafka-streams = { module = &apos;org.apache.kafka:kafka-streams&apos;, version.ref = &apos;managed-kafka&apos; }
...
zipkin-brave-kafka-clients = { module = &apos;io.zipkin.brave:brave-instrumentation-kafka-clients&apos;, version.ref = &apos;zipkin-brave-kafka-clients&apos; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those dependencies will end up in the version catalog that we generate, but &lt;em&gt;without&lt;/em&gt; the &lt;code&gt;managed-&lt;/code&gt; prefix.
This means that we would generate a BOM which contains the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&amp;gt;
  &amp;lt;!-- This module was also published with a richer model, Gradle metadata,  --&amp;gt;
  &amp;lt;!-- which should be used instead. Do not delete the following line which  --&amp;gt;
  &amp;lt;!-- is to indicate to Gradle or any Gradle module metadata file consumer  --&amp;gt;
  &amp;lt;!-- that they should prefer consuming it instead. --&amp;gt;
  &amp;lt;!-- do_not_remove: published-with-gradle-metadata --&amp;gt;
  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  &amp;lt;groupId&amp;gt;io.micronaut.kafka&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;micronaut-kafka-bom&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;5.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
  &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;
  &amp;lt;name&amp;gt;Micronaut Kafka&amp;lt;/name&amp;gt;
  &amp;lt;description&amp;gt;Integration between Micronaut and Kafka Messaging&amp;lt;/description&amp;gt;
  &amp;lt;url&amp;gt;https://micronaut.io&amp;lt;/url&amp;gt;
  &amp;lt;licenses&amp;gt;
    &amp;lt;license&amp;gt;
      &amp;lt;name&amp;gt;The Apache Software License, Version 2.0&amp;lt;/name&amp;gt;
      &amp;lt;url&amp;gt;http://www.apache.org/licenses/LICENSE-2.0.txt&amp;lt;/url&amp;gt;
      &amp;lt;distribution&amp;gt;repo&amp;lt;/distribution&amp;gt;
    &amp;lt;/license&amp;gt;
  &amp;lt;/licenses&amp;gt;
  &amp;lt;scm&amp;gt;
    &amp;lt;url&amp;gt;scm:git@github.com:micronaut-projects/micronaut-kafka.git&amp;lt;/url&amp;gt;
    &amp;lt;connection&amp;gt;scm:git@github.com:micronaut-projects/micronaut-kafka.git&amp;lt;/connection&amp;gt;
    &amp;lt;developerConnection&amp;gt;scm:git@github.com:micronaut-projects/micronaut-kafka.git&amp;lt;/developerConnection&amp;gt;
  &amp;lt;/scm&amp;gt;
  &amp;lt;developers&amp;gt;
    &amp;lt;developer&amp;gt;
      &amp;lt;id&amp;gt;graemerocher&amp;lt;/id&amp;gt;
      &amp;lt;name&amp;gt;Graeme Rocher&amp;lt;/name&amp;gt;
    &amp;lt;/developer&amp;gt;
  &amp;lt;/developers&amp;gt;
  &amp;lt;properties&amp;gt;
    &amp;lt;micronaut.kafka.version&amp;gt;5.0.0-SNAPSHOT&amp;lt;/micronaut.kafka.version&amp;gt;
    &amp;lt;kafka.version&amp;gt;3.4.0&amp;lt;/kafka.version&amp;gt;
  &amp;lt;/properties&amp;gt;
  &amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.apache.kafka&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;kafka-clients&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${kafka.compat.version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.apache.kafka&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;kafka-streams&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${kafka.version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut.kafka&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-kafka&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.kafka.version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut.kafka&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-kafka-streams&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.kafka.version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
  &amp;lt;/dependencyManagement&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note how we automatically translated the &lt;code&gt;managed-kafka&lt;/code&gt; property into a BOM property &lt;code&gt;kafka.version&lt;/code&gt;, which is used in the &lt;code&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/code&gt; block.
Dependencies which do &lt;em&gt;not&lt;/em&gt; start with &lt;code&gt;managed-&lt;/code&gt; &lt;strong&gt;are not included&lt;/strong&gt; in our generated BOM.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s now look at the version catalog that we generate:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;#
# This file has been generated by Gradle and is intended to be consumed by Gradle
#
[metadata]
format.version = &quot;1.1&quot;

[versions]
kafka = &quot;3.4.0&quot;
kafka-compat = &quot;3.4.0&quot;
micronaut-kafka = &quot;5.0.0-SNAPSHOT&quot;

[libraries]
kafka = {group = &quot;org.apache.kafka&quot;, name = &quot;kafka-clients&quot;, version.ref = &quot;kafka-compat&quot; }
kafka-clients = {group = &quot;org.apache.kafka&quot;, name = &quot;kafka-clients&quot;, version.ref = &quot;kafka&quot; }
kafka-streams = {group = &quot;org.apache.kafka&quot;, name = &quot;kafka-streams&quot;, version.ref = &quot;kafka&quot; }
micronaut-kafka = {group = &quot;io.micronaut.kafka&quot;, name = &quot;micronaut-kafka&quot;, version.ref = &quot;micronaut-kafka&quot; }
micronaut-kafka-bom = {group = &quot;io.micronaut.kafka&quot;, name = &quot;micronaut-kafka-bom&quot;, version.ref = &quot;micronaut-kafka&quot; }
micronaut-kafka-streams = {group = &quot;io.micronaut.kafka&quot;, name = &quot;micronaut-kafka-streams&quot;, version.ref = &quot;micronaut-kafka&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Given a &lt;em&gt;single&lt;/em&gt; input, the version catalog that we use to build our Micronaut module, our build conventions let us automatically declare which dependencies should land in the &lt;em&gt;output&lt;/em&gt; BOM and version catalogs that we generate for that project!
Unlike Maven BOMs which either &lt;em&gt;have to&lt;/em&gt; be a parent POM &lt;em&gt;or&lt;/em&gt; redeclare all dependencies in an independent module, in Gradle we can generate these automatically and completely decouple the output BOM from what is required to build our project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In general, all &lt;em&gt;api&lt;/em&gt; dependencies must be managed, so in the example above, the Micronaut Kafka build scripts would have an API dependency on &lt;code&gt;kafka-clients&lt;/code&gt;, which we can find in the main project build script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    api libs.managed.kafka.clients
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The benefit of generating a version catalog for a user is that there is now a &lt;a href=&quot;https://repo1.maven.org/maven2/io/micronaut/kafka/micronaut-kafka-bom/4.5.2/micronaut-kafka-bom-4.5.2.toml&quot;&gt;Micronaut Kafka version catalog published on Maven Central&lt;/a&gt;, alongside the BOM file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This catalog can be imported by a user in their settings file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencyResolutionManagement {
    versionCatalogs {
         create(&quot;mnKafka&quot;) {
             from(&quot;io.micronaut.kafka:micronaut-kafka-bom:4.5.2&quot;)
         }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the dependency on Micronaut Kafka and its managed dependencies can be used in a build script using the &lt;code&gt;mnKafka&lt;/code&gt; prefix:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation mnKafka.micronaut.kafka
    implementation mnKafka.kafka.clients
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A user doesn&amp;#8217;t have to know about the dependency coordinates of Kafka clients: the IDE (at least IntelliJ IDEA) would provide completion automatically!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_bom_composition&quot;&gt;BOM composition&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Micronaut 3.x, there is a problem that we intend to fix in Micronaut 4 regarding our &quot;main&quot; BOM: the Micronaut core BOM is considered as our &quot;platform&quot; BOM, in the sense that it aggregates BOMs of various Micronaut modules.
This makes it hard to release newer versions of Micronaut which, for example, only upgrade particular modules of Micronaut.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore in Micronaut 4, we are cleanly separating the &quot;core&quot; BOM, from the new &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-platform&quot;&gt;platform BOM&lt;/a&gt;.
It is interesting in this blog post because it offers us the opportunity to show how we are capable of generating &lt;em&gt;aggregating BOMs&lt;/em&gt; and &lt;em&gt;aggregated catalogs&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the platform BOM module, you can find the &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-platform/blob/master/gradle/libs.versions.toml&quot;&gt;&quot;input&quot; catalog&lt;/a&gt; that we use, and only consists of &lt;code&gt;managed-&lt;/code&gt; dependencies.
Most of those dependencies are simply dependencies on other Micronaut BOMs: this is an &quot;aggregating&quot; BOM, which imports other BOMs.
This is, therefore, the only BOM that a user would effectively have to use when migrating to Micronaut 4: instead of importing all BOMs for the different Micronaut modules they use, they can simply import the Micronaut Platform BOM, which will then automatically include the BOMs of other modules which &quot;work well together&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This allows us to &lt;strong&gt;decouple the releases&lt;/strong&gt; of the framework from the releases of Micronaut core itself.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, there is a subtlety about aggregating BOMs in Maven: they are not regular dependencies, but dependencies with the &lt;code&gt;import&lt;/code&gt; scope.
This means that we must make a difference between a &quot;managed dependency&quot; and an &quot;imported BOM&quot; in our input catalog.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To do this, we have &lt;em&gt;another&lt;/em&gt; naming convention, which is to use the &lt;code&gt;boms-&lt;/code&gt; prefix for imported BOMs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
...
managed-micronaut-aws = &quot;4.0.0-SNAPSHOT&quot;
managed-micronaut-azure = &quot;5.0.0-SNAPSHOT&quot;
managed-micronaut-cache = &quot;4.0.0-SNAPSHOT&quot;
managed-micronaut-core = &quot;4.0.0-SNAPSHOT&quot;
...

[libraries]
...
boms-micronaut-aws = { module = &quot;io.micronaut.aws:micronaut-aws-bom&quot;, version.ref = &quot;managed-micronaut-aws&quot; }
boms-micronaut-azure = { module = &quot;io.micronaut.azure:micronaut-azure-bom&quot;, version.ref = &quot;managed-micronaut-azure&quot; }
boms-micronaut-cache = { module = &quot;io.micronaut.cache:micronaut-cache-bom&quot;, version.ref = &quot;managed-micronaut-cache&quot; }
boms-micronaut-core = { module = &quot;io.micronaut:micronaut-core-bom&quot;, version.ref = &quot;managed-micronaut-core&quot; }
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This results in the following BOM file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&amp;gt;
  &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
  &amp;lt;groupId&amp;gt;io.micronaut.platform&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;micronaut-platform&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;4.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
  &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;
  &amp;lt;name&amp;gt;Micronaut Platform&amp;lt;/name&amp;gt;
  &amp;lt;description&amp;gt;Bill-Of-Materials (BOM) and Gradle version catalogs for Micronaut&amp;lt;/description&amp;gt;

  ...

  &amp;lt;properties&amp;gt;
    ...
    &amp;lt;micronaut.aws.version&amp;gt;4.0.0-SNAPSHOT&amp;lt;/micronaut.aws.version&amp;gt;
    &amp;lt;micronaut.azure.version&amp;gt;5.0.0-SNAPSHOT&amp;lt;/micronaut.azure.version&amp;gt;
    &amp;lt;micronaut.cache.version&amp;gt;4.0.0-SNAPSHOT&amp;lt;/micronaut.cache.version&amp;gt;
    &amp;lt;micronaut.core.version&amp;gt;4.0.0-SNAPSHOT&amp;lt;/micronaut.core.version&amp;gt;
    ...
  &amp;lt;/properties&amp;gt;
  &amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
      ...
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut.aws&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-aws-bom&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.aws.version}&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut.azure&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-azure-bom&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.azure.version}&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut.cache&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-cache-bom&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.cache.version}&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;io.micronaut&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;micronaut-core-bom&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;${micronaut.core.version}&amp;lt;/version&amp;gt;
        &amp;lt;type&amp;gt;pom&amp;lt;/type&amp;gt;
        &amp;lt;scope&amp;gt;import&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      ...
    &amp;lt;/dependencies&amp;gt;
  &amp;lt;/dependencyManagement&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A more interesting topic to discuss is what we can do with version catalogs that we publish for users: we can &lt;strong&gt;inline dependency aliases&lt;/strong&gt; from each of the imported catalogs into the platform catalog.
All dependencies in the catalog files of each modules are directly available in the platform catalog:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
dekorate = &quot;1.0.3&quot;
elasticsearch = &quot;7.17.8&quot;
...
micronaut-aws = &quot;4.0.0-SNAPSHOT&quot;
micronaut-azure = &quot;5.0.0-SNAPSHOT&quot;
micronaut-cache = &quot;4.0.0-SNAPSHOT&quot;
micronaut-core = &quot;4.0.0-SNAPSHOT&quot;
...

[libraries]
alexa-ask-sdk = {group = &quot;com.amazon.alexa&quot;, name = &quot;ask-sdk&quot;, version = &quot;&quot; }
alexa-ask-sdk-core = {group = &quot;com.amazon.alexa&quot;, name = &quot;ask-sdk-core&quot;, version = &quot;&quot; }
alexa-ask-sdk-lambda = {group = &quot;com.amazon.alexa&quot;, name = &quot;ask-sdk-lambda-support&quot;, version = &quot;&quot; }
aws-java-sdk-core = {group = &quot;com.amazonaws&quot;, name = &quot;aws-java-sdk-core&quot;, version = &quot;&quot; }
aws-lambda-core = {group = &quot;com.amazonaws&quot;, name = &quot;aws-lambda-java-core&quot;, version = &quot;&quot; }
aws-lambda-events = {group = &quot;com.amazonaws&quot;, name = &quot;aws-lambda-java-events&quot;, version = &quot;&quot; }
aws-serverless-core = {group = &quot;com.amazonaws.serverless&quot;, name = &quot;aws-serverless-java-container-core&quot;, version = &quot;&quot; }
awssdk-secretsmanager = {group = &quot;software.amazon.awssdk&quot;, name = &quot;secretsmanager&quot;, version = &quot;&quot; }
azure-cosmos = {group = &quot;com.azure&quot;, name = &quot;azure-cosmos&quot;, version = &quot;&quot; }
azure-functions-java-library = {group = &quot;com.microsoft.azure.functions&quot;, name = &quot;azure-functions-java-library&quot;, version = &quot;&quot; }
...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;alexa-ask-sdk&lt;/code&gt; is for example an alias which was originally declared in the &lt;code&gt;micronaut-aws&lt;/code&gt; module.
Because we aggregate all catalogs, we can inline those aliases and make them directly available in user build scripts:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencyResolutionManagement {
    versionCatalogs {
         create(&quot;mnKafka&quot;) {
             from(&quot;io.micronaut.platform:micronaut-platform:4.0.0-SNAPSHOT&quot;)
         }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
...
    implementation(mn.micronaut.aws.alexa)
    implementation(mn.alexa.sdk)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Generating a version catalog offers us a very pragmatic way to define all dependencies that users can use in their build scripts with guarantees that they work well together.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_technical_details&quot;&gt;Technical details&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you survived reading up to this point, you may be interested in learning how, technically, we implemented this.
You can take a look at our &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-build&quot;&gt;internal build plugins&lt;/a&gt;, but more specifically at the &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-build/blob/master/src/main/groovy/io/micronaut/build/MicronautBomPlugin.java&quot;&gt;BOM plugin&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to generate our BOM and version catalogs, we have mainly 2 inputs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;the list of subprojects which need to participate in the BOM: in a Micronaut modules, we explained that we have several kinds of projects: libraries which are published, test suites, etc. Only a subset of these need to belong to the BOM, and we can determine that list automatically because each project applies a &lt;em&gt;convention plugin&lt;/em&gt; which determines its kind. Only projects of a particular kind are included. Should exceptions be required, we have a &lt;code&gt;MicronautBomExtension&lt;/code&gt; which allows us to configure more precisely what to include or not, via a nice DSL.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the list of dependencies, which is determined from the project&amp;#8217;s version catalog&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One issue is that while Gradle provides automatically the generated, type-safe accessors for version catalogs, there is actually no built-in model that you can access to represent the catalog &lt;em&gt;model&lt;/em&gt; itself (what is an alias, references to versions, etc): the type-safe API represents a &quot;realized&quot; catalog, but not a low-level model that we can easily manipulate.
This means that we had to implement our &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-build/blob/master/src/main/java/io/micronaut/build/catalogs/internal/VersionCatalogTomlModel.java#L29&quot;&gt;own model for this&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We have also seen that we can generate a single platform, aggregating all Micronaut modules for a release, that the users can import into their build scripts.
Unfortunately it is not the case for the Micronaut modules themselves: for example, Micronaut Core &lt;em&gt;must not&lt;/em&gt; depend on other Micronaut modules, but, for example, Micronaut Data can depend on Micronaut SQL and use dependencies from the Micronaut SQL catalog.
Those modules &lt;em&gt;cannot&lt;/em&gt; depend on the platform BOM, because this is the aggregating BOM, so we would create a &lt;em&gt;cyclic dependency&lt;/em&gt; and wouldn&amp;#8217;t be able to release any module.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To mitigate this problem, our internal build plugins expose a DSL which allows each projects to declare which other modules they use:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;micronautBuild {
    importMicronautCatalog() // exposes a `mn` catalog
    importMicronautCatalog(&quot;micronaut-reactor&quot;) // exposes a `mnReactor` catalog
    importMicronautCatalog(&quot;micronaut-rxjava2&quot;) // exposes a `mnRxjava2` catalog
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While this is simple from the &lt;em&gt;declaration site&lt;/em&gt; point of view, it is less practical from a &lt;em&gt;consuming&lt;/em&gt; point of view, since it forces us to use &lt;em&gt;different namespaces&lt;/em&gt; for each imported catalog:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    ...
    testImplementation mn.micronaut.inject.groovy
    testImplementation mnRxjava2.micronaut.rxjava2
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It would have been better if we could actually merge several catalogs into a single one, but unfortunately that feature &lt;a href=&quot;https://github.com/gradle/gradle/issues/20383&quot;&gt;has been removed from Gradle&lt;/a&gt;.
I still have hope that this will eventually be implemented, because not having this creates unnecessary boilerplate in build scripts and redundancy in names (e.g &lt;code&gt;implementation mnValidation.micronaut.validation&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_additional_benefits_and_conclusion&quot;&gt;Additional benefits and conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All that I described in this article aren&amp;#8217;t the only benefits that we have on standardizing on version catalogs.
For example, we have tasks which allow us to check that our generated BOM files only reference dependencies which are actually published on Maven Central, or that there are no SNAPSHOT dependencies when we perform a release.
In the end, while most of the Micronaut developers had no idea what a version catalog was when I joined the team, all of them pro-actively migrated projects to use them because, I think, they immediately saw the benefits and value.
It also streamlined the dependency upgrade process which was still a bit cumbersome before, despite using dependabot.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We now have a very pragmatic way to both use catalogs for building our own projects, and generating BOMs and version catalogs which can be used by both our Maven and Gradle users.
Of course, only the Gradle users will benefit from the version catalogs, but we did that in a way which doesn&amp;#8217;t affect our Maven users (and if you use Maven, I strongly encourage you to evaluate building Micronaut projects with Gradle instead, since the UX is much better).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I cannot end this blog post without mentioning a &quot;problem&quot; that we have today, which is that if you use &lt;a href=&quot;https://micronaut.io/launch&quot;&gt;Micronaut Launch&lt;/a&gt; to generate a Micronaut project, then it will &lt;em&gt;not&lt;/em&gt; use version catalogs.
We have an &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-starter/issues/1385&quot;&gt;issue for this&lt;/a&gt; and pull requests are very welcome!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle&amp;#8217;s flexibility in action</title>
      <link>https://melix.github.io/blog//2023/gradle-synthetic-projects.html</link>
      <pubDate>Mon, 6 Feb 2023 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2023/gradle-synthetic-projects.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I often say that flexibility isn&amp;#8217;t the reason why you should select Gradle to build your projects: reliability, performance, reproducibility, testability are better reasons.
There are, however, cases were its flexibility comes in handy, like last week, when a colleague of mine asked me how we could benchmark a Micronaut project using a variety of combination of features and Java versions.
For example, he wanted to compare the performance of an application with and without epoll enabled, with and without Netty&amp;#8217;s tcnative library, with and without loom support, building both the fat jar and native binary, etc.
Depending on the combinations, the dependencies of the project may be a little different, or the build configuration may be a little different.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was an interesting challenge to pick up and the &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks&quot;&gt;solution turned out to be quite elegant&lt;/a&gt; and very powerful.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conceptual_design&quot;&gt;Conceptual design&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have tried several options before this one, which I&amp;#8217;m going to explain below, but let&amp;#8217;s focus with the &lt;em&gt;final design&lt;/em&gt; (at least at the moment I write this blog post).
The matrix of artifacts to be generated can be configured in the &lt;code&gt;settings.gradle&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;combinations {
    dimension(&quot;tcnative&quot;) {   &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
        variant(&quot;off&quot;)
        variant(&quot;on&quot;)
    }
    dimension(&quot;epoll&quot;) {      &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
        variant(&quot;off&quot;)
        variant(&quot;on&quot;)
    }
    dimension(&quot;json&quot;) {       &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
        variant(&quot;jackson&quot;)
        variant(&quot;serde&quot;)
    }
    dimension(&quot;micronaut&quot;) {  &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
        variant(&quot;3.8&quot;)
        variant(&quot;4.0&quot;)
    }
    dimension(&quot;java&quot;) {       &lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
        variant(&quot;11&quot;)
        variant(&quot;17&quot;)
    }
    exclude {                 &lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
        // Combination of Micronaut 4 and Java 11 is invalid
        it.contains(&quot;micronaut-4.0&quot;) &amp;amp;&amp;amp; it.contains(&quot;java-11&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;a dimension called &lt;code&gt;tcnative&lt;/code&gt; is defined with 2 variants, &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;another dimension called &lt;code&gt;epool&lt;/code&gt; also has &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt; variants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;the &lt;code&gt;json&lt;/code&gt; dimension will let us choose 2 different serialization frameworks: Jackson or Micronaut Serde&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we can also select the version of Micronaut we want to test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;as well as the Java version!&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;some invalid combinations can be excluded&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The generates a number of &lt;em&gt;synthetic Gradle projects&lt;/em&gt;, that is to say &quot;projects&quot; in the Gradle terminology, but without actually duplicating sources and directories on disk.
With the example above, we generate the following projects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-3.8:java-11&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-3.8:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-4.0:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-serde:micronaut-3.8:java-11&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-serde:micronaut-3.8:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-off:json-serde:micronaut-4.0:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-on:json-jackson:micronaut-3.8:java-11&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-on:json-jackson:micronaut-3.8:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;:test-case:tcnative-off:epoll-on:json-jackson:micronaut-4.0:java-17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;#8230;&amp;#8203; and more&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To build the fat jar of the &quot;tcnative on&quot;, &quot;epoll on&quot;, &quot;Jackson&quot;, &quot;Micronaut 4.0&quot; on Java 17 combination, you can invoke:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew :test-case:tcnative-on:epoll-on:json-jackson:micronaut-4.0:java-17:shadowJar&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And building the native image of the &quot;tcnative off&quot;, &quot;epoll on&quot;, &quot;Micronaut Serde&quot;, &quot;Micronaut 3.8&quot; on Java 17 combination can be done with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew :test-case:tcnative-off:epoll-on:json-serde:micronaut-3.8:java-17:nativeCompile&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cherry on the cake, all variants can be built in parallel by executing either &lt;code&gt;./gradlew shadowJar&lt;/code&gt; (for the fat jars) or &lt;code&gt;./gradlew nativeCompile&lt;/code&gt; (for the native binaries), which would copy all the artifacts under the root projects &lt;code&gt;build&lt;/code&gt; directory so that they are easy to find in a single place.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_does_it_work&quot;&gt;How does it work?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a typical project, say the Micronaut application we want to benchmark, you would have a project build which consists of a single Micronaut application module.
For example, running &lt;code&gt;./gradlew build&lt;/code&gt; would build that single project artifacts.
In a multi-project build, you could have several modules, for example &lt;code&gt;core&lt;/code&gt; and &lt;code&gt;app&lt;/code&gt;, and running &lt;code&gt;:core:build&lt;/code&gt; would only build the core library and &lt;code&gt;:app:build&lt;/code&gt; would build both &lt;code&gt;core&lt;/code&gt; and &lt;code&gt;app&lt;/code&gt; (assuming &lt;code&gt;app&lt;/code&gt; depends on &lt;code&gt;core&lt;/code&gt;.
In both cases, single or multi-project builds, for a typical Gradle project, there&amp;#8217;s a &lt;em&gt;real&lt;/em&gt; directory associated for each project &lt;code&gt;core&lt;/code&gt;, &lt;code&gt;app&lt;/code&gt;, etc, where we can find sources, resources, build scripts, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For &lt;em&gt;synthetic projects&lt;/em&gt;, we actually generate Gradle projects (aka modules) programmatically.
We have a skeleton directory, called &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/tree/master/test-case-common&quot;&gt;&lt;code&gt;test-case-common&lt;/code&gt;&lt;/a&gt;, which actually defines our application sources, configuration files, etc.
It also contains a build script which applies a &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/blob/master/build-logic/src/main/kotlin/io.micronaut.testcase.gradle.kts&quot;&gt;single convention plugin&lt;/a&gt;, named &lt;code&gt;io.micronaut.testcase&lt;/code&gt;.
This plugin basically corresponds to our &quot;baseline&quot; build: it applies the Micronaut plugin, adds a number of dependencies, configures native image building, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the &quot;magic&quot; is to use Gradle&amp;#8217;s &lt;a href=&quot;https://melix.github.io/blog/2021/12/composition-in-gradle.html&quot;&gt;composition model&lt;/a&gt; for the variant aspects.
For example, when we define the &lt;code&gt;tcnative&lt;/code&gt; dimension with 2 variants &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt;, we&amp;#8217;re modeling the fact that there are 2 possible outcomes for this dimension.
In practice, enabling &lt;code&gt;tcnative&lt;/code&gt; is just a matter of adding a single dependency at runtime:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;io.micronaut.testcase.tcnative.on.gradle.kts&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;dependencies {
    runtimeOnly(&quot;io.netty:netty-tcnative-boringssl-static::linux-x86_64&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The dimension which handles the version of Java (both to compile and run the application) makes use of Gradle&amp;#8217;s toolchain support:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;io.micronaut.testcase.java.17.gradle.kts&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This can be done in a &lt;em&gt;convention plugin&lt;/em&gt; which is named against the dimension variant name: &lt;code&gt;io.micronaut.testcase.tcnative.on&lt;/code&gt;.
In other words, the project with path &lt;code&gt;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-3.8:java-11&lt;/code&gt; will have a &quot;synthetic&quot; build script which only consists of applying the following plugins:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id(&quot;io.micronaut.testcase&quot;)               &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    id(&quot;io.micronaut.testcase.tcnative.off&quot;)  &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
    id(&quot;io.micronaut.testcase.epoll.off&quot;)     &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
    id(&quot;io.micronaut.testcase.json.jackson&quot;)  &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
    id(&quot;io.micronaut.testcase.micronaut.3.8&quot;) &lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
    id(&quot;io.micronaut.testcase.java.11&quot;)       &lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Applies the common configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Configures &lt;code&gt;tcnative&lt;/code&gt; off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Configures &lt;code&gt;epoll&lt;/code&gt; off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Configures Jackson as the serialization framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Configures Micronaut 3.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Configures build for Java 11&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each of these plugins can be found in our &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/tree/master/build-logic/src/main/kotlin&quot;&gt;build logic&lt;/a&gt;.
As you can see when browsing the build logic directory, there is actually one small optimization: it is not necessary to create a variant script if there&amp;#8217;s nothign to do.
For example, in practice, &lt;code&gt;tcnative&lt;/code&gt; off doesn&amp;#8217;t need any extra configuration, so there&amp;#8217;s no need to write a &lt;code&gt;io.micronaut.testcase.tcnative.off&lt;/code&gt; plugin which would be empty in any case.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_variant_specific_code&quot;&gt;Variant specific code&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The best case would have been that we only have to tweak the build process (for example to add dependencies, disable native image building, etc), but in some cases, we have to change the actual sources or resource files.
Again, we leveraged Gradle&amp;#8217;s flexibility to define custom conventions in our project layout.
In a traditional Gradle (or Maven) project, the main sources are found in &lt;code&gt;src/main/java&lt;/code&gt;.
This is the case here, but we also support adding source directories based on the variants.
For example in this project, some DTOs will make use of Java records on Java 17, but those are not available in Java 11, so we need to write 2 variants of the same classes: one with records, the other one with good old Java beans.
This can be done by putting the Java 11 sources under &lt;code&gt;src/main/&lt;strong&gt;variants&lt;/strong&gt;/java-11/java&lt;/code&gt;, and their equivalent Java 17 sources under &lt;code&gt;src/main/&lt;strong&gt;variants&lt;/strong&gt;/java-17/java&lt;/code&gt;.
This is actually generic: you can use any variant name in place of &lt;code&gt;java-11&lt;/code&gt;: we &lt;em&gt;could&lt;/em&gt;, for example, have a source directory for the &lt;code&gt;epoll-on&lt;/code&gt; folder.
The same behavior is available for resources (in &lt;code&gt;src/main/&lt;strong&gt;variants&lt;/strong&gt;/java-11/resources&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This provides very good flexibility while being totally understandable and conventional.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_the_settings_plugin&quot;&gt;The settings plugin&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So far, we explained how a user interacts with this build, for example by adding a dimension and a variant or adding specific sources, but we didn&amp;#8217;t explain how the projects are actually generated.
For this purpose, we have to explain that Gradle supports multiple types of plugins.
The typical plugins, which we have used so far in this blog post, the &lt;code&gt;io.micronaut.testcase.xxx&lt;/code&gt; plugins, are &lt;em&gt;project plugins&lt;/em&gt;, because they apply on the &lt;code&gt;Project&lt;/code&gt; of a Gradle build.
There are other types of plugins, and the other one which we&amp;#8217;re interested in here is the settings plugin.
Unlike project plugins, these plugins are applied on the &lt;code&gt;Settings&lt;/code&gt; object, that is to say thay they would be typically applied on the &lt;code&gt;settings.gradle(.kts&lt;/code&gt;) file.
This is what we have in this project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle.kts&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;// ...

plugins {
    id(&quot;io.micronaut.bench.variants&quot;)
}


include(&quot;load-generator-gatling&quot;)

configure&amp;lt;io.micronaut.bench.AppVariants&amp;gt; {
    combinations {
        dimension(&quot;tcnative&quot;) {
            variant(&quot;off&quot;)
            variant(&quot;on&quot;)
        }
        dimension(&quot;epoll&quot;) {
            variant(&quot;off&quot;)
            variant(&quot;on&quot;)
        }
        dimension(&quot;json&quot;) {
            variant(&quot;jackson&quot;)
            //variant(&quot;serde&quot;)
        }
        dimension(&quot;micronaut&quot;) {
            variant(&quot;3.8&quot;)
            //variant(&quot;4.0&quot;)
        }
        dimension(&quot;java&quot;) {
            //variant(&quot;11&quot;)
            variant(&quot;17&quot;)
        }
        exclude {
            // Combination of Micronaut 4 and Java 11 is invalid
            it.contains(&quot;micronaut-4.0&quot;) &amp;amp;&amp;amp; it.contains(&quot;java-11&quot;)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;io.micronaut.bench.variants&lt;/code&gt; is another convention plugin &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/blob/master/build-logic/src/main/kotlin/io.micronaut.bench.variants.settings.gradle.kts&quot;&gt;defined in our build logic&lt;/a&gt;.
It doesn&amp;#8217;t do much, except for creating an &lt;em&gt;extension&lt;/em&gt;, which is what lets us configure the variants:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;import io.micronaut.bench.AppVariants

val variants = extensions.create&amp;lt;AppVariants&amp;gt;(&quot;benchmarkVariants&quot;, settings)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The logic actually happens within that &lt;code&gt;AppVariants&lt;/code&gt; class, for which &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/blob/master/build-logic/src/main/kotlin/io/micronaut/bench/AppVariants.kt&quot;&gt;you can find the sources here&lt;/a&gt;.
This class handles both the &lt;code&gt;variants&lt;/code&gt; extension DSL and the logic to generate the projects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The entry point is the &lt;code&gt;combinations&lt;/code&gt; method which takes a configuration block.
Each of the call to &lt;code&gt;dimension&lt;/code&gt; registers a new dimension, which is itself configured via a variant configuration block, where each individual variant is declared.
When we return from this call, we have built a model of dimension of variants, for which we need to compute the cartesian product.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can check each of the entry that we have generated against the excludes, and if the combination is valid, we can use the Gradle APIs which are available in settings script to generate our synthetic projects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;val projectPath = &quot;:test-case:${path.replace(&apos;/&apos;, &apos;:&apos;)}&quot;
settings.include(projectPath)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;computes the project path (with colons) and includes it, which is equivalent to writing this manually in the &lt;code&gt;settings.gradle&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;include(&quot;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-3.8:java-11&quot;)
include(&quot;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-3.8:java-17&quot;)
include(&quot;:test-case:tcnative-off:epoll-off:json-jackson:micronaut-4.0:java-17&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If we stopped here, then we would have defined projects, but Gradle would expect the sources and build scripts for these projects to be found in &lt;code&gt;test-case/tcnative-off/epoll-off/json-jackson/micronaut-3.8/java-11&lt;/code&gt;.
This isn&amp;#8217;t the case for us, since all projects will share the same project directory (&lt;code&gt;test-case-common&lt;/code&gt;).
However, if we configure all the projects to use the same directory, then things could go wrong at build time, in particular because we use parallel builds: all the projects would write their outputs in the same &lt;code&gt;build&lt;/code&gt; directory, but as we have seen, they may have different sources, different dependencies, etc.
So we need to set both the project directory to the common directory, but &lt;em&gt;also&lt;/em&gt; change the build directory to a per-project specific directory.
This way we make sure to reuse the same sources without having to copy everything manually, but we also make sure that up-to-date checking, build caching and parallel builds work perfectly fine:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;settings.project(projectPath).setProjectDir(File(settings.rootDir, &quot;test-case-common&quot;))
gradle.beforeProject {
    if (this.path == projectPath) {
        setBuildDir(File(projectDir, &quot;build/${path}&quot;))
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that we have to use the &lt;code&gt;gradle.beforeProject&lt;/code&gt; API for this: it basically provides us with the naked &lt;code&gt;Project&lt;/code&gt; instance of our synthetic projects, before its configuration phase is triggered.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next step is to make sure that once the &lt;code&gt;java&lt;/code&gt; plugin is applied on a project, we configure the additional source directories for each dimension.
This is done via the &lt;code&gt;withPlugin&lt;/code&gt; API which lets use react on the application of a plugin, and the &lt;code&gt;SourceSet&lt;/code&gt; API:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;project.plugins.withId(&quot;java&quot;) {
    project.extensions.findByType(JavaPluginExtension::class.java)?.let { java -&amp;gt;
        variantNames.forEach { variantName -&amp;gt;
            java.sourceSets.all {
                this.java.srcDir(&quot;src/$name/variants/$variantName/java&quot;)
                this.resources.srcDir(&quot;src/$name/variants/$variantName/resources&quot;)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last, we need to apply our convention plugins, the plugins which correspond to a specific combination variant, to our synthetic project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;gradle.afterProject {
    if (this.path == projectPath) {
        variantSpecs.forEach {
            val pluginId = &quot;io.micronaut.testcase.${it.dimensionName}.${it.name}&quot;
            val plugin = File(settings.settingsDir, &quot;build-logic/src/main/kotlin/$pluginId.gradle.kts&quot;)
            if (plugin.exists()) {
                plugins.apply(pluginId)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, for each variant, we basically compute the name of the plugin to apply, and if a corresponding file exists, we simply apply the plugin, that&amp;#8217;s it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It only takes around 100 lines of code to implement both the DSL and logic to generate all this, which is all the power Gradle gives us!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_limitations&quot;&gt;Limitations&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, there are limitations to this approach. While we could handle the Java version easily, we can&amp;#8217;t, however, add a dimension we would have needed : GraalVM CE vs GraalVM EE.
This is a &lt;a href=&quot;https://github.com/gradle/gradle/pull/18028&quot;&gt;limitation of Gradle&amp;#8217;s toolchain support&lt;/a&gt;, which cannot make a difference between those 2 toolchains.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another limitation is that this works well for a &lt;em&gt;single project build&lt;/em&gt;, or a project like here where there&amp;#8217;s a common application, a support library, but all modifications happen in a single project (the application).
Supporting multi-project builds and variants &lt;em&gt;per module&lt;/em&gt; would be possible in theory, but would add quite a lot of complexity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was also lucky that I could support both Micronaut 3 and Micronaut 4: in practice, the Gradle plugin for Micronaut 4 isn&amp;#8217;t compatible with Micronaut 3, so I would have to either use Micronaut 3 or Micronaut 4.
However, we can use the Micronaut 4 plugin with Micronaut 3, provided &lt;a href=&quot;https://github.com/yawkat/micronaut-http-benchmarks/blob/master/build-logic/src/main/kotlin/io.micronaut.testcase.micronaut.3.8.gradle.kts#L9-L14&quot;&gt;some small tweaks&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last, there is one unknown to this, which is that building synthetic projects like that makes use of APIs which are stable in Gradle, but likely to be deprecated in the future (event based APIs).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_alternatives&quot;&gt;Alternatives&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before going to the &quot;final&quot; solution, I have actually tried a few things (which could be spiked in a couple hours or so).
In particular, the first thing I did was actually to use a &lt;em&gt;single project&lt;/em&gt;, but configure additional artifacts (e.g jar and native binary) for each variant.
While I could make it work, the implementation turned out to be more complicated, because you have to understand how each of the plugins work (Micronaut, GraalVM, the Shadow plugin) and create exotic tasks to make things work.
Also this had a number of drawbacks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;impossible to build variants in parallel (at least without the experimental configuration cache)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;configuring each of the variant specific build configuration (e.g adding dependencies) was more complicated. It was in particular only possible to add additional &lt;em&gt;runtime&lt;/em&gt; dependencies. If something else was needed, for example compile time dependencies or additional resources, this wasn&amp;#8217;t possible to do because a &lt;em&gt;single&lt;/em&gt; main jar was produced.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, we have seen how we can leverage Gradle&amp;#8217;s flexibility to support what seemed to be a complicated use case: given a common codebase and some &quot;small tweaks&quot;, generate a matrix of builds which are used to build different artifacts, in order to benchmark them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The solution turned out to be quite simple to implement, and I hope pretty elegant, both in terms of user facing features (adding dimensions and configuring the build should be easy), maintenance (composition over inheritance makes it very simple to understand how things are combined) and implementation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Many thanks to &lt;a href=&quot;https://infosec.exchange/@yawkat&quot;&gt;Jonas Konrad&lt;/a&gt; for the feature requests and for reviewing this blog post!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Petit voyage en électrique</title>
      <link>https://melix.github.io/blog//2023/tourainetech-208.html</link>
      <pubDate>Fri, 20 Jan 2023 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2023/tourainetech-208.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hier, je me déplaçais sur Tours pour la conférence &lt;a href=&quot;https://touraine.tech&quot;&gt;Touraine Tech&lt;/a&gt;, où j&amp;#8217;ai donné un talk sur &lt;a href=&quot;https://speakerdeck.com/melix/micronaut-test-resources-25fbfffd-adfe-4c93-aada-aa3a5538bcde&quot;&gt;Micronaut Test Resources&lt;/a&gt;.
Je remercie encore l&amp;#8217;organisation d&amp;#8217;avoir accepté ce talk, qui, d&amp;#8217;après les commentaires que j&amp;#8217;ai reçu, a plutôt été bien reçu !
Mais ça n&amp;#8217;est pas le sujet de ce billet : je souhaite simplement vous parler de mon expérience avec ma voiture électrique, que j&amp;#8217;ai utilisé pour me rendre à la conférence.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_déplacement&quot;&gt;Le déplacement&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Tours, ça n&amp;#8217;est pas si loin de chez moi, environ 200km.
J&amp;#8217;avais donc décidé de m&amp;#8217;y rendre avec mon e-208, dont l&amp;#8217;autonomie théorique, avec sa batterie de 50kW (disponible 46kW), est annoncée à 340km.
J&amp;#8217;ai fais l&amp;#8217;acquisition de cette voiture il y a 2 ans, et j&amp;#8217;en suis globalement très content : j&amp;#8217;habite en zone rurale, nous n&amp;#8217;avons pas de transports en commun, et cette voiture sert donc pour tous les trajets du quotidien.
Je peux la recharger à la maison sans problème.
Jusqu&amp;#8217;ici, les trajets les plus longs que j&amp;#8217;avais effectué étaient &lt;em&gt;sans recharge&lt;/em&gt; : des allez-retours à Pornic, où j&amp;#8217;ai de la famille, soit environ 160 km aller/retour, et ça se passait très bien, en particulier l&amp;#8217;été.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Maintenant, entre l&amp;#8217;autonomie théorique et la réalité, il y a un monde, en particulier en hiver.
J&amp;#8217;étais donc assez nerveux à l&amp;#8217;idée de me retrouver &quot;en rade&quot; avant d&amp;#8217;arriver sur Tours, et j&amp;#8217;ai donc planifié mon déplacement avec l&amp;#8217;application ChargeMap (j&amp;#8217;ai une carte chez eux et l&amp;#8217;application Peugeot est franchement pas top, impossible de planifier aussi bien).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je voulais faire l&amp;#8217;aller-retour dans la journée, ce qui impliquait de pouvoir recharger en arrivant sur Tours.
Un des problèmes, c&amp;#8217;est que les bornes de recharge &quot;rapides&quot; ne sont pas si nombreuses.
Autre problème : il est impossible de savoir si une borne va être occupée lorsqu&amp;#8217;on y arrivera.
La 208 dispose d&amp;#8217;une prise combo CCS qui accepte une charge à 100kW.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;avais donc 2 choix:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;m&amp;#8217;arrêter à une charge rapide (50kW et +) avant de me rendre à la conférence&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ou déposer ma voiture sur une borne lente à proximité de la conférence et revenir plus tard dans la journée pour libérer la borne&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai choisi la première option, parce que j&amp;#8217;avais un doute que la borne soit occupée en arrivant, et que je doive donc faire 10 min de route de plus pour me rendre à la borne rapide et donc perdre du temps.
Par ailleurs, ça n&amp;#8217;est pas super pratique que de devoir quitter la conférence et marcher 1km (potentiellement sous la pluie) dans la journée.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En bref, j&amp;#8217;ai planifié pour être &lt;em&gt;tranquille&lt;/em&gt;. Voici les conditions du trajet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;départ 5h32, tout le trajet en mode éco&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;je suis parti avec une batterie chargée à 100% (je sais qu&amp;#8217;il faut éviter, mais d&amp;#8217;une, je n&amp;#8217;allais pas risquer de devoir m&amp;#8217;arrêter sur une borne lente en cours de trajet, je ne souhaitais pas me retrouver à moins de 10% de batterie à l&amp;#8217;arrivée, trop stressant, et d&amp;#8217;autre part, le logiciel Peugeot ne &lt;em&gt;permet pas&lt;/em&gt; d&amp;#8217;interrompre une charge lorsque la batterie atteint une certaine limite, par exemple 80% !)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j&amp;#8217;ai choisi un itinéraire &lt;em&gt;sans autoroute&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;j&amp;#8217;ai roulé à 80km sur les départementales (y compris celles limitées à 90km/h, en Maine et Loire), entre 90 et 100km/h sur les nationales&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;je roule en conduite souple : pas d&amp;#8217;accélérations brutales, utilisation du mode B pour freiner, etc&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;la température extérieure oscillait entre 0 et 3 degrés, chauffage réglé à 18&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;application ChargeMap dispose d&amp;#8217;une fonctionnalité qui lui permet d&amp;#8217;envoyer le trajet planifié sur Google Maps, que j&amp;#8217;ai utilisé pour le guidage.
Ça se passait très bien, jusqu&amp;#8217;à ce que j&amp;#8217;arrive après Saumur où je me rends compte que le GPS avait décidé de me faire prendre l&amp;#8217;autoroute !
Problème, je n&amp;#8217;avais clairement pas assez d&amp;#8217;autonomie pour rouler à 130 km/h.
Ne pouvant pas rouler à 90 km/h sur autoroute, trop dangereux, je suis donc monté à 110 km/h et autant dire que vu les conditions météo (froid), mon autonomie restante fondait comme neige au soleil.
Je suis donc sorti un peu plus loin pour finir le trajet en passant par les bords de Loire, comme c&amp;#8217;était initialement prévu.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au final, je suis arrivé sur ma borne de recharge Allego, au Casino de La Riche, à 8h08 : 180km en 2h36.
De mémoire (l&amp;#8217;appli Peugeot récupère les trajets, mais pas la consommation, incroyable ce retard du logiciel par rapport à la concurrence !), ma consommation moyenne était de l&amp;#8217;ordre de 16kWh/100km.
Je me suis branché et j&amp;#8217;ai chargé pendant 49 minutes pour atteindre 90% de batterie, soit 29kW, facture: 31,38€, pas franchement économique (1.082€ du kWh !).
Je me suis arrêté à 90% parce que la recharge &quot;ralentit&quot; à mesure qu&amp;#8217;on s&amp;#8217;approche de la charge maximale : il m&amp;#8217;aurait fallu rester encore une bonne demi-heure (voire plus) pour atteindre les 100%, et je souhaitais me rendre à la conférence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis donc arrivé sur Polytech&amp;#8217;Tours à 9h12, soit 3h40, à comparer aux 2h25 si j&amp;#8217;étais parti avec ma 407 diesel, qui ferait l&amp;#8217;aller-retour sans aucun pb sans faire le plein (autonomie environ 950km&amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour le retour, je savais donc que je serai très juste et qu&amp;#8217;il faudrait probablement que je fasse un arrêt supplémentaire pour recharger (à cause des 10% de batterie en moins au départ).
Je ne suis &lt;em&gt;pas&lt;/em&gt; passé par l&amp;#8217;autoroute au retour, et donc suivi les bords de Loire.
Les conditions météo étaient similaires, mais avec plus de pluie.
J&amp;#8217;ai surveillé mon autonomie, et si au départ, j&amp;#8217;avais une marge de 100km entre l&amp;#8217;autonomie annoncée par la voiture (c&amp;#8217;est à dire qu&amp;#8217;en suivant ses indications, je serais à la maison avec 100km d&amp;#8217;autonomie restante), au fur et à mesure du trajet, cette estimation a sensiblement baissé. Arrivé à Cholet (environ 40km de chez moi), il ne restait plus que 60 km de marge, alors que j&amp;#8217;avais baissé la température dans l&amp;#8217;habitacle à 16 degrés.
Encore une fois, je roulais en mode éco, souple, pas de bouchons, rien.
En clair, l&amp;#8217;estimation d&amp;#8217;autonomie, c&amp;#8217;est du grand n&amp;#8217;importe quoi et complètement irréaliste (à noter, qu&amp;#8217;en été, c&amp;#8217;est bien plus proche de la réalité).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, j&amp;#8217;avais aussi faim et n&amp;#8217;étant pas très joueur, je me suis arrêté sur une borne rapide en chemin, à côté d&amp;#8217;une pizzeria, au SIEML de l&amp;#8217;Ecuyère.
Comme je savais que quel que soit le temps de charge, j&amp;#8217;aurais de quoi rentrer large, j&amp;#8217;ai juste pris le temps de manger.
Je récupère ma voiture, pas mal, 22,7kW de récupérés en 35 minutes de charge, pour 9.62€ : &lt;strong&gt;3 fois moins cher que la recharge à Tours&lt;/strong&gt; (mais à comparer aux 0.14€/kWh quand je charge à la maison&amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;expérience fut concluante : je sais que je peux faire ce genre de trajets, moyennant quelques concessions (heure d&amp;#8217;arrivée tardive à cause de la recharge à l&amp;#8217;arrivée, trajet sans autoroute, confort &quot;limité&quot;, etc), mais c&amp;#8217;est à peu près la distance maximale que je puisse faire sans que ça ne devienne trop pénible.
En revanche, je reste très mitigé sur l&amp;#8217;autonomie &quot;réelle&quot; : ici, j&amp;#8217;étais plus proche des 200 km en faisant tout pour économiser.
Même en conditions idéales, jamais, ô grand jamais, je n&amp;#8217;atteindrais les 340 km (le mieux, c&amp;#8217;est environ 300km).
Le logiciel est aussi bien trop basique comparé à la concurrence (oui, Tesla) : l&amp;#8217;application mobile manque de fonctionnalités de base (blocage de charge, récupération des consommations, &amp;#8230;&amp;#8203;) et le GPS pour planifier un trajet est franchement nul.
L&amp;#8217;estimation de l&amp;#8217;autonomie restante est irréaliste et pire, on ne sait pas vraiment où on en est de charge: l&amp;#8217;indicateur à la &quot;jauge d&amp;#8217;essence&quot; n&amp;#8217;est pas adapté à une batterie (dites moi le % restant, c&amp;#8217;est plus parlant !).
Enfin, un des gros soucis reste la recharge et les tarifs hallucinants qui sont pratiqués : il est pour ainsi dire impossible de savoir combien va vous coûter un trajet, puisqu&amp;#8217;en fonction des conditions, vous allez devoir vous arrêter, ou non, et que les tarifs varient en fonction de la puissance de recharge, du fournisseur, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lorsqu&amp;#8217;on part en thermique, on sait que le carburant coûte environ 1.9€/L, à 25% près : en électrique, oubliez. Vous pouvez faire du simple au quadruple.
Est-ce à dire que je ne recommande pas l&amp;#8217;électrique ? Pas du tout ! Déjà, je préfère 100 fois le confort de la conduite en électrique au thermique. La voiture est aussi super agréable à conduire et la puissance disponible immédiatement est un indéniable atout de l&amp;#8217;électrique.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mon alternative, sur ce trajet, aurait été de prendre ma voiture thermique, mais ça aurait été la solution de facilité.
Et compte-tenu de l&amp;#8217;urgence climatique, j&amp;#8217;ai fais le choix de perdre un peu de confort, pour le bien de ma conscience :)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Un an d&amp;#8217;astrophotographie</title>
      <link>https://melix.github.io/blog//2022/12/astrophoto-2022-fr.html</link>
      <pubDate>Sat, 31 Dec 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/12/astrophoto-2022-fr.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
An english version of this blog post is available &lt;a href=&quot;https://melix.github.io/blog/2022/12/astrophoto-2022.html&quot;&gt;here&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et voilà, 2022, c&amp;#8217;est terminé !
Je poste régulièrement des images de l&amp;#8217;univers que je prends depuis mon jardin, mais il est possible que vous en ayez raté quelques unes (je les postais sur Twitter, mais désormais, vous pouvez me suivre sur &lt;a href=&quot;https://astrodon.social/@melix&quot;&gt;un compte astro dédié sur Mastodon&lt;/a&gt;), c&amp;#8217;est donc l&amp;#8217;opportunité de faire une rétrospective !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prendre de belles photo du ciel demande un peu d&amp;#8217;effort : bien entendu, il faut du matériel (télescope, caméras, &amp;#8230;&amp;#8203;), de bonnes conditions (météo, phase de la lune, &amp;#8230;&amp;#8203;) mais il faut aussi de l&amp;#8217;expérience dans le traitement logiciel.
Les photos que je prends ces temps-ci sont déja bien meilleures que celles que je prenais il y a quelques années.
Néanmoins, j&amp;#8217;y vois de nombreux défauts, du bruit, des problèmes de focus, etc.
Il y a donc encore beaucoup de choses à améliorer.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_deux_sessions_twitch&quot;&gt;Deux sessions Twitch&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette année, j&amp;#8217;ai fait deux sessions lives sur Twitch, où j&amp;#8217;ai expliqué &lt;em&gt;de mon point de vue&lt;/em&gt; les bases de l&amp;#8217;astrophotographie.
Il s&amp;#8217;agit de deux sessions d&amp;#8217;environ 90 minutes chacune, où je donne des informations sur le matériel, mon setup, mais aussi le traitement logiciel.
Je les ai faites pour répondre à des questions qu&amp;#8217;on me pose souvent, comme:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;quel télescope choisir ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;combien de temps de pose faut-il ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;combien ça coûte ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;comment fais-tu pour prendre une photo ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si vous avez un peu de temps, voici les liens:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Hudtta97gDU&quot;&gt;Astrophotographie, partie 1 - Le matériel&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tSgnOtdjVHs&quot;&gt;Astrophotographie, partie 2 - Les miracles du logiciel&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2022_les_photos&quot;&gt;2022: Les photos&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je vais les lister par ordre chronologique.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Les photos que je poste ici sont protégées par le droit d&amp;#8217;auteur: vous ne pouvez ni les recopier, ni les revendre, sans ma permission.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;De temps en temps, il peut s&amp;#8217;écouler des semaines entre les photos, auquel cas il s&amp;#8217;agit très certainement de problèmes météo : dès que j&amp;#8217;en ai l&amp;#8217;opportunité, vous pouvez être certains que je sors le matériel !
Cependant, il peut arriver qu&amp;#8217;il s&amp;#8217;agisse aussi d&amp;#8217;un échec : paramètres de capture incorrects, mauvais focus, mauvaises poses de flats, &amp;#8230;&amp;#8203; Dans ce cas, il n&amp;#8217;y a guère d&amp;#8217;autre choix que de mettre tout le travail à la poubelle&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour chacune des photos que je vous propose ici, il s&amp;#8217;agit d&amp;#8217;une version basse résolution.
Pour voir les versions hautes résolution, cliquez sur la photo, ce qui vous amènera vers sa version sur &lt;a href=&quot;https://www.astrobin.com/users/melix/&quot;&gt;mon compte Astrobin&lt;/a&gt;.
Vous aurez alors accès:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;à tous les détails d&amp;#8217;acquisition (quand, temps de pose, matériel utilisé, filtres, etc)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;à une version &quot;full&quot; en haute résolution.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La plupart de mes photos font 62 megapixels. Parfois moins, parfois plus, mais il s&amp;#8217;agit grossièrement de 7 fois plus de pixels que sur votre télé 4K !
Lorsque vous arriverez sur Astrobin, vous tomberez sur une version &quot;annotée&quot;, mais basse résolution de la photo.
Cliquez dessus et vous aurez alors accès à la version &quot;full&quot;, qui est considérablement plus détaillée.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est parti !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_janvier&quot;&gt;Janvier&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous sommes en période de fêtes, alors commençons par NGC 2264, aussi connu sous le nom de &quot;l&amp;#8217;arbre de Noël&quot;.
Il s&amp;#8217;agit d&amp;#8217;un amas ouvert à environ 2300 années lumières, dans la constellation de la Licorne, qui se trouve accompagné d&amp;#8217;une magnifique nébuleuse appelée la nébuleuse du cône.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/40y572/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-01-12-christmas-tree-cluster.jpg&quot; alt=&quot;2022 01 12 christmas tree cluster&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pendant l&amp;#8217;hiver, les nuits sont relativement longues, ce qui donne souvent l&amp;#8217;opportunité de travailler plusieurs sujets en une nuit.
J&amp;#8217;en ai donc profité pour capturer une autre cible, NGC 4565, la &quot;galaxie de l&amp;#8217;aiguille&quot;, un classique.
Je n&amp;#8217;ai pas pris suffisamment de données pour bien faire ressortir les couleurs, néamnoins le résultat est intéressant:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/kdbd9i/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-01-12-ngc-4565.jpg&quot; alt=&quot;2022 01 12 ngc 4565&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_février&quot;&gt;Février&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A la fin de l&amp;#8217;hiver, presque un mois plus tard, j&amp;#8217;ai choisi une cible bien connue des astrophotographes : &lt;a href=&quot;https://fr.wikipedia.org/wiki/NGC_1893&quot;&gt;NGC 1893&lt;/a&gt;.
Cette photo a été assez difficile à prendre et à traiter, à cause de la présence d&amp;#8217;étoiles très brillantes dans le champ, ce qui, avec mon matériel, crée des reflets qu&amp;#8217;il faut supprimer en traitement.
Ce traitement pourrait même être améliorer pour réduire un peu plus les étoiles et faire ressortir la nébuleuse plus clairement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/po5nml/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-02-26-ic-410.jpg&quot; alt=&quot;2022 02 26 ic 410&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous débutons alors la &quot;saison des galaxies&quot;, qui dure tout le printemps.
La prochaine image est un autre classique, le couple de galaxies M81 et M82.
Je ne suis pas complètement satisfait du traitement de cette photo, notamment au niveau des couleurs, mais il s&amp;#8217;agissait pour moi de faire ressortir ce qu&amp;#8217;on appelle l&amp;#8217;IFN, les &lt;a href=&quot;https://en.wikipedia.org/wiki/Integrated_Flux_Nebula&quot;&gt;Nébuleuses de flux intégré&lt;/a&gt;, qui ne sont ni plus ni moins que de très larges nuages de gaz &quot;inerte&quot; qui s&amp;#8217;étendent sur de très grandes distances.
C&amp;#8217;est particulièrement visible dans cette photo.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/idzr7f/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-02-26-m81-m82.jpg&quot; alt=&quot;2022 02 26 m81 m82&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_mars&quot;&gt;Mars&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La prochaine photo est un autre classique du printemps, connu sur le nom de &quot;la chaîne de Markarian&quot;.
Bien que le grand public connaisse l&amp;#8217;existence des galaxies et parfois des amas d&amp;#8217;étoiles (notre soleil fait partie de la galaxie de la Voie Lactée), peu de personnes savent que les galaxies elle-mêmes s&amp;#8217;organisent en &quot;groupes locaux&quot; puis sous forme de structures plus larges s&amp;#8217;étendant sur des milliers d&amp;#8217;années lumières.
Cette photographie a le mérite de montrer ces groupes de façon évidente : sur une seule photographie, nous pouvons voir des dizaines de galaxies, parfois en intéraction directe (elles tournent les unes autour des autres et pourront fusionner), parfois simplement en arrière plan.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/xz6zv3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-03-23-Markarian-chain.jpg&quot; alt=&quot;2022 03 23 Markarian chain&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_mai&quot;&gt;Mai&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le mois d&amp;#8217;avril ne fut pas un bon mois, sans la moindre photo !
Alors quand Mai fut venu et le beau temps de retour, j&amp;#8217;en ai profité et pris plein les mirettes !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La saison des galaxies n&amp;#8217;est pas complètement terminée en Mai.
J&amp;#8217;ai choisi de capturer une galaxie dont la forme rappelle celle de la galaxie de l&amp;#8217;aiguille: NGC 5746.
Encore une fois sur cette photo, le traitement a été difficile à cause de la présence de cette étoile très brillante.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/yfxsfc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-09-ngc-5746.jpg&quot; alt=&quot;2022 05 09 ngc 5746&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Continuons avec une des photos les plus spectaculaires de cette année.
Elle n&amp;#8217;est pas particulièrement nette et il y a des efforts à faire sur le traitement, mais il s&amp;#8217;agissait là d&amp;#8217;une occasion à ne pas manquer : la photographie d&amp;#8217;un événement rare, une &lt;em&gt;supernova&lt;/em&gt;, c&amp;#8217;est à dire une étoile qui meurt dans une explosion phénoménale, en émettant une quantité de lumière si impressionnante qu&amp;#8217;elle surpasse celle du reste de la galaxie : une supernova dans une galaxie va atteindre une luminosité apparente aussi forte que des étoiles de notre propre galaxie, alors qu&amp;#8217;elle peut se situer à des centaines de milliers d&amp;#8217;années lumières de nous !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La photo est aussi spectaculaire au sens où j&amp;#8217;a utilisé une focale longue, pour &quot;zoomer&quot; au plus près, mais que malgré celà, de nombreuses autres galaxies sont visibles en arrière plan dans le champ !
Voici donc la supernova 2022hfs, dans la galaxie NGC 4647.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sur la photo, au centre, nous avons la grande galaxie M60, et dessous, son compagnon NCG 4647.
Dans cette dernière, on distingue en haut un point brillant: il s&amp;#8217;agit de la supernova !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/pbjfny/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-07-supernova-m60.jpg&quot; alt=&quot;2022 05 07 supernova m60&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Afin de changer des galaxies, j&amp;#8217;ai aussi capturé en mai le magnifique amas globulaire nommé M5.
Un amas globulaire est un ensemble de &quot;vieilles&quot; étoiles, regroupées dans un espace très compact.
On trouve de nombreux amas globulaires au sein de notre galaxie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/5wn7o0/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-07-m5.jpg&quot; alt=&quot;2022 05 07 m5&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai une fascination pour les &quot;nébuleuses sombres&quot;.
Ce sont des nébuleuses de différents types, qui présentent des couleurs sombres pour différentes raisons: poussière interstellaire, qui bloque la lumière, ou plus simplement des régions du ciel dénuées des gas qui émettent typiquement dans le rouge.
Faire ressortir ces nébuleuses sombre requiert en général beaucoup de temps de pose.
En mai, ça reste possible, mais c&amp;#8217;est difficile, et il faut même parfois cumuler les données de plusieurs nuits.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai pris deux photos de telles nébuleuses en Mai.
La première montre B347 et LDN 889, dans la constellation du Cygne.
Il s&amp;#8217;agit d&amp;#8217;une nébuleuse en émission (elle émet sa propre lumière) qui montre une région plus sombre en son centre:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ytssu6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-28-ldn-914.jpg&quot; alt=&quot;2022 05 28 ldn 914&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La seconde est une magnifique structure complexe, mélange de gaz bloquants la lumière, de nébuleuses à réflexion (qui reflètent la lumière des étoiles) et à émission : IC 4603.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/0r1zyg/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-29-ic_4603.jpg&quot; alt=&quot;2022 05 29 ic 4603&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En règle générale, j&amp;#8217;évite la lune : je préfère photographier le ciel profond (galaxies, nébuleuses, &amp;#8230;&amp;#8203;), ce qui requiert un ciel sombre, sans lune et sans pollution lumineuse.
Cependant, je m&amp;#8217;accorde de temps en temps une pause, ce que j&amp;#8217;ai fait le 10 mai, en capturant notre voisine:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/lokkfc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-10-moon.jpg&quot; alt=&quot;2022 05 10 moon&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_juin&quot;&gt;Juin&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En juin débute la saison des nébuleuses et en particulier des nébuleuses à émission (dans le rouge).
Pendant quelques mois, nous allons pouvoir capturer beaucoup d&amp;#8217;entre elles : ceci s&amp;#8217;explique par la position de la voie lactée, qui en été se trouve au zénith au-dessus de nos têtes.
Nous observons alors vers le centre de notre galaxie, où la densité d&amp;#8217;étoiles et de nuages de gas est la plus forte.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un des classique, c&amp;#8217;est la nébuleuse de l&amp;#8217;Aigle, que j&amp;#8217;avais déja capturée.
Je me suis donc lancé le défi de réaliser une mosaïque qui couvrirait une région assez large du ciel, de M16 à M24.
La photo qui en résulte ne fait pas moins de 7360 pixels de large, pour 13200 de haut !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/cmwruf/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-30-M16-M17-M18-M24.jpg&quot; alt=&quot;2022 05 30 M16 M17 M18 M24&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La photo suivante est ma &quot;favorite&quot; en 2022.
En comparaison à d&amp;#8217;autres photos, elle ne m&amp;#8217;a pas demandé beaucoup de temps de pose : seulement une heure, mais elle montre une des plus belles régions du ciel.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;étais particulièrement envieux de prendre cette photo, parce qu&amp;#8217;il est assez difficile de regrouper les conditions nécessaires là où j&amp;#8217;habite : entre la météo et le fait que cette cible ne monte pas très haut dans le ciel, le timing était serré et je l&amp;#8217;ai ratée plusieurs années de suite.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Trèves de bavardages, il s&amp;#8217;agit donc des nébuleuses de la Trifide et du Lagon, qui, comme je l&amp;#8217;ai dit, sont pour moi une des plus belles régions du ciel avec un mélange subtil de couleurs bleutées (nébuleuse en émission), rosée et rouge, avec de nombreux détails visibles dans les nébulosités.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ft7dra&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-30-trifid-lagoon-nebulas-v2.jpg&quot; alt=&quot;2022 05 30 trifid lagoon nebulas v2&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lorce qu&amp;#8217;on est astronome amateur, un des premiers objets du ciel profond que l&amp;#8217;on essaie de voir l&amp;#8217;été en Europe est la nébuleuse de la Lyre, M57.
Il s&amp;#8217;agit d&amp;#8217;une nébuleuse planétaire (nommée ansi parce que les premiers observateurs les ont confondu avec des planètes) assez petite, mais très lumineuse, visible avec des instruments très modestes.
La prendre en photo et faire ressortir des détails, en revanche, est une autre paire de manches.
Pour cette photo, j&amp;#8217;ai utilisé une technique inhabituelle, réservée d&amp;#8217;habitude aux planètes : capturer de très nombreuses poses très courtes et &quot;assembler&quot; le tout.
Voici le résultat:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/nc88w9/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-17-m57-ring-nebula.jpg&quot; alt=&quot;2022 06 17 m57 ring nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le 28 juin est une date spéciale, puisqu&amp;#8217;il s&amp;#8217;agit de mon anniversaire de mariage (20 ans en 2023 !).
En 2022, le 28 juin me fit un beau cadeau avec de nombreuses photos.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La première est la nébuleuse du croissant, dans le Cygne: il s&amp;#8217;agit d&amp;#8217;une étoile qui a explosé et dont l&amp;#8217;enveloppe gazeuse s&amp;#8217;étend au milieu d&amp;#8217;une gigantesque milieu gazeux rouge où naîtront de nouvelles étoiles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ee98nj/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-NGC-6888-crescent-nebula.jpg&quot; alt=&quot;2022 06 27 NGC 6888 crescent nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La 2ème est un autre classique des astrophotographes : la nébuleuse de la trompe d&amp;#8217;éléphant (Tr-37).
Je vous ai dis que j&amp;#8217;aimais les nébuleuses sombres, cette photo montre de superbes structures sombres au sein d&amp;#8217;une nébuleuse brillante, le contraste est saisissant !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/8k54oe/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-tr37-elephant-trunk-nebula.jpg&quot; alt=&quot;2022 06 27 tr37 elephant trunk nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un autre exemple d&amp;#8217;une telle nébuleuse est NGC 7822, capturée la même nuit :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/awvk46/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-28-Ced-214-NGC-7822.jpg&quot; alt=&quot;2022 06 28 Ced 214 NGC 7822&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, pour conclure le mois de juin, il s&amp;#8217;agit de vous montrer ce que l&amp;#8217;on finit par voir après quelques milliers d&amp;#8217;années, lorsqu&amp;#8217;une supernova relativement proche explose.
Le ciel d&amp;#8217;été dispose d&amp;#8217;un magnifique exemple dans la constellation du Cygne : la nébuleuse des &quot;dentelles du Cygne&quot;, nommée ainsi en référence à ses magnifiques structures en filaments, de véritables &quot;dentelles&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/8hbi6d/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-veil-nebula.jpg&quot; alt=&quot;2022 06 27 veil nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_juillet&quot;&gt;Juillet&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le mois de juillet est la période idéale pour capturer notre voisine la plus proche, la galaxie d&amp;#8217;Andromède.
Légèrement plus grande que notre propre galaxie, la Voie Lactée, nos deux comparses finiront par fusionner dans quelques millions d&amp;#8217;années.
Andromède est visible à l&amp;#8217;oeil nu sous un bon ciel sans pollution lumineuse.
Sa taille apparente est même supérieuse à celle de la Lune !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/15de5a/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-04-andromeda-galaxy.jpg&quot; alt=&quot;2022 07 04 andromeda galaxy&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il y a de nombreuses comètes dans notre système solaire, et de temps en temps, une d&amp;#8217;entre elles devient suffisamment brillante pour qu&amp;#8217;on puisse la capturer.
C&amp;#8217;est arrivé pour moi au début du mois de Juillet, quand la comète C2017 K2 Panstarrs est devenue visible :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-06-c2017-k2-panstarrs.jpg&quot; alt=&quot;2022 07 06 c2017 k2 panstarrs&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;(pour une raison inconnue je n&amp;#8217;ai pas posté cette photo sur Astrobin).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ma cible suivante est un nouvel exemple de &quot;nébuleuse sombre&quot;, cette fois ci sur une nébuleuse qui l&amp;#8217;est de part des nuages de poussières interstellaires, qui empêchent la lumière des étoiles en fond de nous parvenir.
Celle-ci est connue sous le nom de la nébuleuse de l&amp;#8217;hippocampe.
Mon champ est cependant suffisamment large pour montrer, dans la même photo, 2 autres objets très intéressants: l&amp;#8217;amas ouvert NGC 6939, ainsi que la magnifique galaxie spirale NGC 6946, vue du dessus.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/frun9u/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-06-seahorse-nebula-ngc-6946.jpg&quot; alt=&quot;2022 07 06 seahorse nebula ngc 6946&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour ma prochaine cible, j&amp;#8217;ai choisi un objet plus difficile à prendre en photo : une nébuleuse à émission diffuse, connue sous le nom de Shapless 115 (du catalogue de nébuleuses du même nom).
Prendre en photo de telles nébuleuses requiert l&amp;#8217;utilisation de filtres en bande étroite, en particulier dans les endroits soumis à la pollution lumineuse, ce qui est mon cas (bien qu&amp;#8217;elle soit bien plus raisonnable qu&amp;#8217;à Nantes, 45 km plus au nord). Elle requiert aussi des temps de pose plus longs (ici, 4 heures) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/m1x3ny/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-31-Sh2-115-116-112.jpg&quot; alt=&quot;2022 07 31 Sh2 115 116 112&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le même jour, j&amp;#8217;ai essayé de prendre en photo la &quot;nébuleuse du sorcier&quot;, mais je fus assez déçu du résultat, que je n&amp;#8217;ai donc pas posté sur Astrobin.
Mais puisqu&amp;#8217;il s&amp;#8217;agit d&amp;#8217;une rétrospective, je vous la pose ici, sachant que je réessairai certainement cette cible en 2023:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-26-ngc-7380-wizard-nebula.jpg&quot; alt=&quot;2022 07 26 ngc 7380 wizard nebula&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_août&quot;&gt;Août&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La prochaine photographie est une autre de mes favories en 2022, et une autre nébuleuse sombre.
Il s&amp;#8217;agit de la &quot;nébuleuse du requin&quot;, j&amp;#8217;espère que vous voyez pourquoi :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/eptl8u/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-01-ldn-1235-shark-nebula.jpg&quot; alt=&quot;2022 08 01 ldn 1235 shark nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Vous ne voyez pas le requin ? Essayez avec cette version &quot;sans étoiles&quot; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-01-ldn-1235-shark-nebula-starless.jpg&quot; alt=&quot;2022 08 01 ldn 1235 shark nebula starless&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour la prochaine photographie, vous reconnaîtrez un visage familier : Andromède, une nouvelle fois !
Pourquoi la prendre en photo plusieurs fois ?
Eh bien parce bien que ce soit une cible très grande et très lumineuse, il s&amp;#8217;agit aussi d&amp;#8217;une des plus difficile à traiter.
Il faut donc essayer plusieurs techniques, plusieurs temps de pose, etc pour obtenir un bon résultat.
Alors, quelle version préférez vous ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/7z12bt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-27-andromeda-galaxy.jpg&quot; alt=&quot;2022 08 27 andromeda galaxy&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous voici déja à la fin de l&amp;#8217;été, mais il restait une photographie que je ne pouvais pas me permettre de rater : Messier 33, la galaxie du triangle.
Il s&amp;#8217;agit d&amp;#8217;une autre galaxie de notre groupe local, avec Andromède, qui est absolument magnifique avec ses couleurs bleutées.
Si vous zoomez sur la photos, vous y découvrirez de nombreuses régions rougeâtres ou rosées: il s&amp;#8217;agit des mêmes types de nébuleuses que celles que j&amp;#8217;ai montré précédement, où naissent de nombreuses nouvelles étoiles !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/h3s597/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-28-m33-pinwheel.jpg&quot; alt=&quot;2022 08 28 m33 pinwheel&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_septembre&quot;&gt;Septembre&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le mois de Septembre marque le début de la &quot;saison des pluies&quot;, qui peut durer jusque février.
Il reste encore quelques bonnes opportunités en septembre avant que cette saison ne commence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour la première photo, nous avons NGC 7822, dont je ne suis pas particulièrement fier du traitement, avec de nombreux gradients encore visibles&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/x1coyx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-18-NGC-7822.jpg&quot; alt=&quot;2022 09 18 NGC 7822&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La suivante est un autre &quot;inmanquable&quot;, les nébuleuses de l&amp;#8217;Amérique du Nord et du Pélican : cette photo est une mosaique de 2 images, n&amp;#8217;hésitez donc pas à vous promener sur la version &quot;full&quot;, qui révèle un nombre impressionnant de détails.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/nqk6iu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-18-North-America-and-Pelican.jpg&quot; alt=&quot;2022 09 18 North America and Pelican&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour la suivante, vous retrouverez encore une fois une figure familière : Messier 33.
Mais cette fois-ci, j&amp;#8217;ai utilisé une autre focale, plus longue, permettant de zoomer sur la galaxie qui prenait alors l&amp;#8217;intégralité du capteur, c&amp;#8217;était juste parfait !
Là encore je vous invite à vous balader sur la version &quot;full&quot;, qui montre nombre de détails&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/vxx62e/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-20-Triangulum-Galaxy-M33.jpg&quot; alt=&quot;2022 09 20 Triangulum Galaxy M33&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_novembre&quot;&gt;Novembre&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je vous avais dit qu&amp;#8217;après Septembre, ça devenait compliqué&amp;#8230;&amp;#8203; Entre fin septembre et fin novembre, pas la moindre photo !
Alors quand j&amp;#8217;ai eu une petite fenêtre le 29, et peu de temps avant le retour de la pluie, j&amp;#8217;ai choisi de partir sur une cible &quot;facile&quot; et très lumineuse, qui ne requiert donc pas beaucoup de temps de pose: la fameuse nébuleuse d&amp;#8217;Orion !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/in06bo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-11-29-orion-m42.jpg&quot; alt=&quot;2022 11 29 orion m42&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La nuit suivante, j&amp;#8217;ai eu une nouvelle chance, où j&amp;#8217;ai choisi de cibler la très photogénique NGC 1333, une région du ciel qui montre dans un même champ des nébuleuses sombres, mais aussi de lumineuses nébuleuses à réflection, presque blanches, et une région rougeâtre où naissent de nombreuses étoiles formant un magnifique contraste avec la région sombre alentour !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/o5k14v/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-11-30-ngc-1333.jpg&quot; alt=&quot;2022 11 30 ngc 1333&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_decembre&quot;&gt;Decembre&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour terminer l&amp;#8217;année, une photo qui n&amp;#8217;a que quelques jours.
J&amp;#8217;ai dù attendre le lendemain de Noël pour pouvoir ressortir le matériel (et profiter de mes vacances).
Les conditions étaient loin d&amp;#8217;être parfaites : de nombreux passages nuageux, un ciel pas super transparent, et une humidité qui finit par tomber en brume.
Cependant, cette cible me fait de l&amp;#8217;oeil depuis de nombreuses années, et là encore, il s&amp;#8217;agit d&amp;#8217;une cible qu&amp;#8217;on ne peut pas capturer facilement de part sa hauteur, très basse sur l&amp;#8217;horizon.
La &quot;fenêtre de capture&quot; est donc très courte, et j&amp;#8217;aurais aimé disposer de plus de temps de pose pour faire ressortir des couleurs du &quot;casque de Thor&quot; que voici:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ks39ts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-12-26-ngc-2359-Thor_s_Helmet.jpg&quot; alt=&quot;2022 12 26 ngc 2359 Thor s Helmet&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et nous y voilà ! J&amp;#8217;aurais bien sûr aimé en faire plus. Mais entre les pleines lunes, les conditions météo et n&amp;#8217;oublions pas mon travail, c&amp;#8217;est toujours un peu compliqué.
Il y a de très nombreux objets que je souhaite prendre en photo, et que j&amp;#8217;ai soit raté, soit pas eu l&amp;#8217;occasion ou le temps de faire lorsqu&amp;#8217;ils étaient visibles.
Qu&amp;#8217;à celà ne tienne, c&amp;#8217;est aussi pour ça que l&amp;#8217;astrophotographie, c&amp;#8217;est une passion d&amp;#8217;une vie !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>One year of astrophotography</title>
      <link>https://melix.github.io/blog//2022/12/astrophoto-2022.html</link>
      <pubDate>Sat, 31 Dec 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/12/astrophoto-2022.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Une version en français est disponible &lt;a href=&quot;https://melix.github.io/blog/2022/12/astrophoto-2022-fr.html&quot;&gt;ici&lt;/a&gt; !
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is it, 2022 is coming to an end!
I am regularly posting pictures of the universe I take from my backyards, but you may have missed some of them (note: I used to post them on Twitter, but now that I moved to Mastodon, I have &lt;a href=&quot;https://astrodon.social/@melix&quot;&gt;a dedicated account for this&lt;/a&gt;), so this is the opportunity to recap!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Making great photos of the sky takes some effort: of course you need some gear (telescope, camera, &amp;#8230;&amp;#8203;), you need good conditions (weather, moon, &amp;#8230;&amp;#8203;) but you also need skills in software post-processing.
The photos I take those days are already much better than the ones I used to take a few years ago, but I see a lot of defects, noise, focusing problems, etc. so there&amp;#8217;s still a LOT of room for improvement.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_couple_of_twitch_sessions_in_french&quot;&gt;A couple of Twitch sessions (in french)&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This year, for the french speaking, I have done a couple of sessions on Twitch where I explained the basics of astrophotography, &lt;em&gt;from my point of view&lt;/em&gt;.
It&amp;#8217;s a couple of ~90 minutes videos each, where I give some details about my setup, the gear, and software processing.
I&amp;#8217;ve done this because I&amp;#8217;m always getting the same questions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;what telescope to choose?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how long does it take?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how much does it cost?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how do you proceed?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are interested (and french speaking), here are the links:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Hudtta97gDU&quot;&gt;Astrophotographie, partie 1 - Le matériel&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=tSgnOtdjVHs&quot;&gt;Astrophotographie, partie 2 - Les miracles du logiciel&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let me know if you are interested in seeing something similar in English.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2022_the_photos&quot;&gt;2022: The photos&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m going to list the photos in chronological order.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
The photos I&amp;#8217;m posting here are copyrighted, you &lt;em&gt;may not&lt;/em&gt; use them or sell them without my permission.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sometimes, there are weeks between photos, and that&amp;#8217;s almost certainly because of the weather: when I have the opportunity, you can be sure I always take the setup out.
However, sometimes, it&amp;#8217;s also because I failed: you capture data, but you made a mistake (e.g, incorrect focus, not enough exposure, wrong flat frames, &amp;#8230;&amp;#8203;), and you have to drop everything&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For each of the photos I&amp;#8217;m posting here, it&amp;#8217;s a low resolution version.
You can click on each of the photos to get a link to their &lt;a href=&quot;https://www.astrobin.com/users/melix/&quot;&gt;version on Astrobin&lt;/a&gt;, which will also give you:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;acquisition details (when, how many exposures, filters, &amp;#8230;&amp;#8203;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a full resolution version : most of the photos are 62-megapixel (sometimes less because of cropping, sometimes more because of mosaics), which is roughly 7 times as many pixels as what you have in a 4K UHD TV!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that when you&amp;#8217;re on Astrobin, you can click on the photo to go to the full version, which has considerably higher resolution than the preview.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_january&quot;&gt;January&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s the holiday season, so let&amp;#8217;s get started with NGC 2264 also known as the &quot;Christmas Tree Cluster&quot;: it&amp;#8217;s an open star cluster about 2300 light years away, located in the Monoceros constellation, which also shows a beautiful nebula called the &quot;Cone nebula&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/40y572/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-01-12-christmas-tree-cluster.jpg&quot; alt=&quot;2022 01 12 christmas tree cluster&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;During winter nights are quite long, which also gave me the opportunity to shot another target, NGC 4565 aka the Needle Galaxy, a classic.
I didn&amp;#8217;t get enough data to properly capture the colors, but it&amp;#8217;s still an interesting shot!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/kdbd9i/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-01-12-ngc-4565.jpg&quot; alt=&quot;2022 01 12 ngc 4565&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_februrary&quot;&gt;Februrary&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Late winter, more than a month after the previous photos, I went for a target which is well known of astrophotographers: &lt;a href=&quot;https://en.wikipedia.org/wiki/NGC_1893&quot;&gt;NGC 1893&lt;/a&gt;.
It was an image which proved difficult to make and process, because of the presence of the bright stars which created colorful reflections on my very fast setup.
Processing can probably also be improved to reduce the stars and show the nebula better.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/po5nml/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-02-26-ic-410.jpg&quot; alt=&quot;2022 02 26 ic 410&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This opens the &quot;galaxy season&quot;, which is lasting almost all spring. The next image is a &quot;classic&quot;, the M81 and M82 couple, but I&amp;#8217;m not super happy with the processing and resulting colors.
This image has &lt;em&gt;lots&lt;/em&gt; of details, and especially, I wanted to highlight the &lt;a href=&quot;https://en.wikipedia.org/wiki/Integrated_Flux_Nebula&quot;&gt;Integrated Flux Nebula&lt;/a&gt; which is clearly visible in this sector of the sky.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/idzr7f/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-02-26-m81-m82.jpg&quot; alt=&quot;2022 02 26 m81 m82&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_march&quot;&gt;March&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next photo is another classic of the galaxy season, known as Markarian&amp;#8217;s chain.
It is lesser known to the public that while stars are grouped in clusters and galaxies, galaxies themselves are organized in larger, extremely wide structures called local groups or chains.
Those galaxies are bound together by gravity, and Markarian&amp;#8217;s chain is a spectacular example of this, with a small area of the sky showing dozens of galaxies in interaction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/xz6zv3/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-03-23-Markarian-chain.jpg&quot; alt=&quot;2022 03 23 Markarian chain&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;April wasn&amp;#8217;t a good period, with no photo whatsoever, unfortunately, but May was the most prolific of period of the year!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_may&quot;&gt;May&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Galaxy season isn&amp;#8217;t over in May. I chose to image another galaxy which looks similar to the needle galaxy: NGC 5746.
Yet, again, processing proved to be difficult because of the very bright star below it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/yfxsfc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-09-ngc-5746.jpg&quot; alt=&quot;2022 05 09 ngc 5746&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Galaxy season continues with probably one of the most interesting photos of this year.
It isn&amp;#8217;t particularly sharp, and there&amp;#8217;s a lot of progress to be made on processing this image, but it was an opportunity I couldn&amp;#8217;t miss: taking a picture of a Supernova, that is to say a star which dies by exploding and emitting so much light that its brightness literally makes it stand out of the galaxy hosting it.
The photo is also spectacular in the sense that it&amp;#8217;s taken with a long focal length, in order to &quot;zoom&quot; as much as possible, but still shows a lot of other galaxies in this small area of the sky!
Here is Supernova 2022hfs in NGC 4647: in the middle we can see the M60 galaxy and its companion NGC 4647.
In that galaxy, at the upper top, we can see a bright spot which is the supernova:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/pbjfny/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-07-supernova-m60.jpg&quot; alt=&quot;2022 05 07 supernova m60&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another classic of the dark skies is the beautiful M5 globular cluster:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/5wn7o0/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-07-m5.jpg&quot; alt=&quot;2022 05 07 m5&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have a fascination for &quot;dark nebulas&quot;, which are nebulas which show dark structures, usually because of the presence of dust which blocks light, or simply because some large gas structures are not uniform.
Usually taking photos of such structures requires &lt;em&gt;time&lt;/em&gt;, long exposures, which is still possible during that period of the year, but becoming complicated.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I took a couple pictures of such nebulas in May.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First one is B347 and LDN 889 in Cygnus which is showing an emission nebula with a nice dark area in its center:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ytssu6/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-28-ldn-914.jpg&quot; alt=&quot;2022 05 28 ldn 914&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second one is a beautiful complex structure showing dust blocking light and creating uncanny colored structures: IC 4603.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/0r1zyg/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-29-ic_4603.jpg&quot; alt=&quot;2022 05 29 ic 4603&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Usually, I&amp;#8217;m avoiding the moon: I prefer the beauties of deep sky objects which require very dark skies and no light pollution.
However, from time to time, I like to give the moon a shot, which is what I did on May 10th:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/lokkfc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-10-moon.jpg&quot; alt=&quot;2022 05 10 moon&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_june&quot;&gt;June&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;June is the beginning of the &quot;emission nebula&quot; season.
There are a lot of good targets that we can start shooting during summer.
One of the classics is the Eagle nebula, which I had already shot. So I wanted to capture this area in wider field.
This is why I started with a mosaic which is extremely detailed if you go to the full picture below: the image is 7360 pixels wide, for 13200 pixels height!
The area covers the region from M16 to M24:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/cmwruf/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-30-M16-M17-M18-M24.jpg&quot; alt=&quot;2022 05 30 M16 M17 M18 M24&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next photo is probably my favorite of 2022.
In comparison to other photos which literally requires hours of exposure, this one &quot;only&quot; took an hour, but it shows one of the most beautiful areas of the sky.
I was particularly eager to do it, because it&amp;#8217;s difficult to have good conditions to capture it where I live: it&amp;#8217;s relatively low in the sky, so there is unfortunately a very short period of time when the conditions are met to capture it, and when you do so, you can&amp;#8217;t capture a lot of data.
In any case, here are the Trifid and Lagoon nebulas, as I said, probably one of my favorites, showing beautiful colors and well visible gas structures:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ft7dra&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-05-30-trifid-lagoon-nebulas-v2.jpg&quot; alt=&quot;2022 05 30 trifid lagoon nebulas v2&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When you are an amateur astronomer, one of the first targets you try to see (especially in European summer) is the ring nebula (M57) in Lyrae.
It is a very bright nebula which is easily visible even with modest instruments.
Taking a picture of it and getting details of its structure is harder.
Here, I took an ususual approach, by going full focal length and taking lots of short exposures with my planetary camera and processing the image as if it was a planet.
Here&amp;#8217;s what I got:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/nc88w9/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-17-m57-ring-nebula.jpg&quot; alt=&quot;2022 06 17 m57 ring nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;June 28 is a special day for me as it&amp;#8217;s my wedding&amp;#8217;s day (it&amp;#8217;s going to be 20 years in 2023!).
June 28, 2022 was also a prolific day with a couple of beautiful nebulas.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first one is the crescent nebula in Cygnus, which is an incredibly dense area of the sky, in the middle of the Milky Way, with lots of gas and stars:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ee98nj/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-NGC-6888-crescent-nebula.jpg&quot; alt=&quot;2022 06 27 NGC 6888 crescent nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The 2d photo I took that day was another classic of astrophotographers, the Elephant Trunk Nebula (Tr-37).
I told you I loved dark nebulas, this one is a good example of dark structures in a bright nebula:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/8k54oe/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-tr37-elephant-trunk-nebula.jpg&quot; alt=&quot;2022 06 27 tr37 elephant trunk nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another example of such a nebula is NGC 7822:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/awvk46/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-28-Ced-214-NGC-7822.jpg&quot; alt=&quot;2022 06 28 Ced 214 NGC 7822&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least of June, what happens after a star explodes as a supernova? The Veil Nebula, in Cygnus, is a great illustration of the result.
This nebula is one of the most remarkable example of its kind, because it&amp;#8217;s particularly large and shows very nice structures of filaments of matter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/8hbi6d/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-06-27-veil-nebula.jpg&quot; alt=&quot;2022 06 27 veil nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_july&quot;&gt;July&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Summer is the best period of time to take a photo of our nearest neighbor galaxy, the famous Andromeda galaxy.
It is visible with the naked eye (if no moon is present) and larger than the apparent size of the moon in the sky.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/15de5a/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-04-andromeda-galaxy.jpg&quot; alt=&quot;2022 07 04 andromeda galaxy&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sometimes you get the opportunity to capture comets.
This happened for me in the beginning of July, when comet C2017 K2 Panstarrs became bright enough to be shot:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-06-c2017-k2-panstarrs.jpg&quot; alt=&quot;2022 07 06 c2017 k2 panstarrs&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;(for some reason I didn&amp;#8217;t put this one on Astrobin).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My next target was another example of &quot;dark nebula&quot;, this time with a nebula which is dark because of dust blocking the light around it.
This one is known as the Seahorse Nebula.
Interestingly, the field I captured was wide enough to add a couple of interesting targets in the area: the open cluster NGC 6939 and the beautiful galaxy NGC 6946:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/frun9u/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-06-seahorse-nebula-ngc-6946.jpg&quot; alt=&quot;2022 07 06 seahorse nebula ngc 6946&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the next one I chose a more difficult target, a diffuse emission nebula known as Sharpless 115.
Such nebulas require filters to be captured properly under conditions like mine where there is light pollution (reasonable but still), and longer exposures (4 hours in this case):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/m1x3ny/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-31-Sh2-115-116-112.jpg&quot; alt=&quot;2022 07 31 Sh2 115 116 112&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The same day I captured the &quot;Wizard Nebula&quot; but wasn&amp;#8217;t happy enough with the result, so I didn&amp;#8217;t post it on Astrobin.
Here&amp;#8217;s the photo, though. I will definitly retry this target in 2023:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-07-26-ngc-7380-wizard-nebula.jpg&quot; alt=&quot;2022 07 26 ngc 7380 wizard nebula&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_august&quot;&gt;August&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next image is another of my 2022 favorites, and another dark nebula. This one is called the shark nebula, and I hope you&amp;#8217;ll figure out why:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/eptl8u/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-01-ldn-1235-shark-nebula.jpg&quot; alt=&quot;2022 08 01 ldn 1235 shark nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can&amp;#8217;t see the shark? Maybe it&amp;#8217;s easier with this &quot;starless&quot; version?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-01-ldn-1235-shark-nebula-starless.jpg&quot; alt=&quot;2022 08 01 ldn 1235 shark nebula starless&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next image will be familiar, it&amp;#8217;s the Andromeda galaxy, once again!
Why capturing it multiple times? Well, as I said, the more data you gather, the better. Also processing is difficult, and you have to make a lot of trial to find the right exposure and number of frames to get a good result.
Here&amp;#8217;s my 2d attempt, which one do you prefer?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/7z12bt/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-27-andromeda-galaxy.jpg&quot; alt=&quot;2022 08 27 andromeda galaxy&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Summer is ending, but there was one target I couldn&amp;#8217;t miss: another galaxy of our local group, Messier 33, the Triangulum galaxy. This spiral galaxy is particularly magnificient with its blue&amp;#8217;ish colors.
If you zoom in the photo, you&amp;#8217;ll also notice red clouds, which are nebulas where new stars are regularly formed!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/h3s597/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-08-28-m33-pinwheel.jpg&quot; alt=&quot;2022 08 28 m33 pinwheel&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_september&quot;&gt;September&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the end of summer comes the rainy season, which lasts up to february.
September gives us a few last opportunities.
The first image, NGC 7822, I&amp;#8217;m not super happy with, there are still gradients visible, but let me share it anyway, it&amp;#8217;s a retro!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/x1coyx&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-18-NGC-7822.jpg&quot; alt=&quot;2022 09 18 NGC 7822&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next one is another classic of astrophoto, the North America and Pelican nebulas, which has the particularity of being a mosaic of 2 images, so if you go to the full version and zoom in, you will see a LOT of details:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/nqk6iu/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-18-North-America-and-Pelican.jpg&quot; alt=&quot;2022 09 18 North America and Pelican&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next one will again sound familiar: it&amp;#8217;s the triangulum galaxy again, but with a longer focal length, which, in practice, means that it&amp;#8217;s &quot;zoomed in&quot; compared to the previous version.
I can only encourage you to dig into the full version, which shows an incredible amount of details, definitely another of my favorites of 2022!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/vxx62e/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-09-20-Triangulum-Galaxy-M33.jpg&quot; alt=&quot;2022 09 20 Triangulum Galaxy M33&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_november&quot;&gt;November&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I told you that the rainy season starts after September, so clearly, between october, and even till the end of November, I wasn&amp;#8217;t able to capture a single target!
I had a small window on November 29, not much time before rain, so I chose an &quot;easy target&quot;, the famous Orion Nebula, which is so bright it doesn&amp;#8217;t take long to capture:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/in06bo/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-11-29-orion-m42.jpg&quot; alt=&quot;2022 11 29 orion m42&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next day I was able to go to a target I wanted to shoot for a long time.
NGC 1333 is an area of the sky which shows a variety of nebulas in the same field of view: dark nebulas, but also a light, blue&amp;#8217;ish emission nebula, and a red area where new stars are born!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/o5k14v/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-11-30-ngc-1333.jpg&quot; alt=&quot;2022 11 30 ngc 1333&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_december&quot;&gt;December&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Finally, the last picture of this year is from a few days ago.
I had to wait after Christmas to get another window, and I chose to try to capture the so-called &quot;Thor&amp;#8217;s Helmet&quot;.
Unfortunately the weather conditions weren&amp;#8217;t great, with lots of clouds and eventually fog, so I didn&amp;#8217;t get as much data as I would like.
This target is particularly difficult because it&amp;#8217;s very low, so if I couldn&amp;#8217;t capture it now, it would be too late after&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/ks39ts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img src=&quot;/blog/img/astro/retro2022/2022-12-26-ngc-2359-Thor_s_Helmet.jpg&quot; alt=&quot;2022 12 26 ngc 2359 Thor s Helmet&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And it&amp;#8217;s a wrap! I wish I could do much more photos, but between the moon, the weather conditions and&amp;#8230;&amp;#8203; my daily job, it&amp;#8217;s always a bit complicated.
There are many objects I would have liked to capture, but either failed or missed the window when they are visible.
This is why astrophotography is a lifetime hobby, after all!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Monitoring pour optimiser ma conso électrique</title>
      <link>https://melix.github.io/blog//2022/11/monitoring-elec.html</link>
      <pubDate>Sat, 26 Nov 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/11/monitoring-elec.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En juillet dernier, j&amp;#8217;ai fait installer des panneaux solaires.
Cette installation change considérablement nos habitudes de consommation: au lieu de consommer de préférence aux heures creuses, il est préférable de consommer lorsque la production locale le permet.
Dans ce billet, je vous explique ce que j&amp;#8217;ai mis en place pour nous aider dans l&amp;#8217;optimisation de notre consommation, en particulier un outil de monitoring avec un Raspberry PI.
L&amp;#8217;objectif de mon projet est de réduire ma facture électrique en maximisant l&amp;#8217;autoconsommation.
Nous allons donc voir comment l&amp;#8217;installation des panneaux peut changer nos habitudes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/elec/moniteur-sep.jpg&quot; alt=&quot;moniteur sep&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_installation_de_panneaux_solaires&quot;&gt;Installation de panneaux solaires&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il y a longtemps que l&amp;#8217;idée nous trottait dans la tête.
En effet, ici, nous chauffions au fioul, ce qui avait un certain nombre d&amp;#8217;inconvénients: pollution (fort émetteur de CO₂), prix très variable (entre 800€ et 1400€ les 1000L selon les saisons), bruit (la chaudière), odeurs de combustion, etc.
Cette chaudière au fioul nous servait à la fois à chauffer l&amp;#8217;eau chaude, mais aussi au chauffage domestique.
La maison étant relativement bien isolée, nous arrivions cependant, à 4 personnes, à ne consommer qu&amp;#8217;environ 1000L de fioul par an.
Une vieille chaudière à fioul était tombée en panne en plein hiver, il y a 5 ans, nous avions dû la changer en urgence, et, je me souviens très bien de cela, il se trouve que j&amp;#8217;étais à ce moment à l&amp;#8217;étranger pour le &quot;Gradle World Meeting&quot;, une semaine de travail avec l&amp;#8217;ensemble de l&amp;#8217;équipe.
Nous n&amp;#8217;avions donc pas eu le temps de faire différents devis, notamment de chauffage alternatif.
Mais en Mars dernier, patatras, nouvelle panne.
Cette fois-ci, la chaudière elle-même n&amp;#8217;était pas en cause: c&amp;#8217;est le système d&amp;#8217;alimentation en fioul, entre la cuve et la chaudière, qui était encrassé.
La chaudière se mettait constamment en défaut faute d&amp;#8217;avoir une arrivée de fioul propre.
Nous avions alors le choix entre faire nettoyer la cuve et la tuyauterie, pour une facture de l&amp;#8217;ordre de 2k€, ou de changer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En même temps, mon épouse et moi-même sommes tous les 2 en télétravail 5j/5.
Notre consommation électrique est donc importante, entre l&amp;#8217;alimentation des ordinateurs, des écrans, la cuisine le midi, le chauffage d&amp;#8217;appoint dans mon bureau, &amp;#8230;&amp;#8203;
Certains de nos équipements consomment aussi régulièrement: n&amp;#8217;ayant pas le tout à l’égout, par exemple, nous avons une microstation de traitement des eaux usées, avec une pompe de recirculation et une pompe de relevage, qui ont des consommations non négligeables à l&amp;#8217;année.
Nous possédons aussi une voiture électrique (une e-208) qui est chargée à domicile.
Enfin, l&amp;#8217;été, nous avons une pompe de circulation pour la piscine qui consomme beaucoup.
Au final, notre facture électrique est donc beaucoup plus importante que celle de fioul.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette dernière panne a donc été l&amp;#8217;occasion de revoir notre projet.
Après divers devis, nous avons opté pour l&amp;#8217;installation de 16 panneaux solaires de la société française &lt;a href=&quot;https://dualsun.com/&quot;&gt;DualSun&lt;/a&gt; : 10 panneaux classiques &quot;Flash&quot; et 6 panneaux hybrides électricité/eau chaude, pour une production totale de 6kWC (6 kW crète).
Les panneaux hybrides permettent de produire de l&amp;#8217;électricité &lt;strong&gt;et&lt;/strong&gt; de préchauffer l&amp;#8217;eau chaude.
Le tout a été associé à une pompe à chaleur air-eau, une Alfea Extensa A.I de la marque française &lt;a href=&quot;https://www.atlantic.fr/Chauffer-le-logement/Pompe-a-chaleur/Aerothermie/Aerothermie-Air-Eau/Alfea-Extensa-A.I.-et-Alfea-Extensa-Duo-A.I&quot;&gt;Atlantic&lt;/a&gt;.
Il s&amp;#8217;agit d&amp;#8217;une pompe à chaleur air-eau moyenne température (55⁰C) qui nous permet de conserver notre installation de chauffages en fonte, au prix (à déterminer) d&amp;#8217;une consommation supérieure lors des grands froids (ce qui n&amp;#8217;arrive pas souvent ici).
La pompe est associée à un ballon d&amp;#8217;eau chaude qui exploite le circuit préchauffé par les panneaux.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les 6kWc nous permettent d&amp;#8217;être en auto-consommation totale en journée l&amp;#8217;été (et probablement une partie du printemps/automne, à confirmer avec le temps) et je devrais pouvoir revendre une partie de la surproduction à Enedis (mais pour des raisons administratives, mon dossier est toujours en attente&amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mon calcul de retour sur investissement m&amp;#8217;a donné 12 ans, en prenant en compte une augmentation annuelle de 5% des prix de l&amp;#8217;électricité.
Si les tarifs augmentent plus vite, alors ça sera rentabilisé plus vite, mais il est impossible de savoir si ça sera le cas&amp;#8230;&amp;#8203; a priori avec la crise énergétique, j&amp;#8217;ai tendance à croire que ça n&amp;#8217;est pas un mauvais calcul&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, nous n&amp;#8217;avons &lt;strong&gt;pas&lt;/strong&gt; fait installer de batteries: bien que cela serait extrêmement intéressant dans mon cas, pour récupérer la nuit le surplus de la production en journée, le prix des batteries est encore bien trop élevé (de l&amp;#8217;ordre de 7k€ pour 10kW).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_changer_ses_habitudes_de_consommation&quot;&gt;Changer ses habitudes de consommation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans mon cas, nos habitudes de consommation étaient assez simples, au final:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;en journée, nous n&amp;#8217;avions pas trop le choix: il faut bien alimenter les ordinateurs, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;les machines à laver, lave-vaisselle, etc tournaient la nuit pour profiter des heures creuses&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Malheureusement, notre consommation en heures creuses était assez limitée comparée au reste.
Tout à changé avec les panneaux solaires:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;cet été et même fin septembre, lorsque le ciel est dégagé, mes panneaux produisent jusqu&amp;#8217;à 5.5kW, ce qui dépasse largement ma consommation &quot;live&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous chargeons la voiture en journée via la prise &quot;domestique&quot; (~2kW) lorsque c&amp;#8217;est possible, et la nuit en charge &quot;rapide&quot; (6kW) lorsque la batterie est trop basse&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;les machines tournent en journée au lieu de la nuit&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais optimiser tout cela est &lt;strong&gt;compliqué&lt;/strong&gt;, et je souhaitais un système qui permette à mon épouse et mes enfants de savoir si, par exemple, &quot;c&amp;#8217;est le moment&quot; de lancer une machine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je me suis donc lancé dans un projet de &quot;bidouille&quot; pour faire un système de monitoring qui donnerait en direct ma production, ma consommation, et indiquerait de manière simple si on a de la marge ou pas.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_petite_complication&quot;&gt;Petite complication&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Évidemment, vous pourriez vous dire que ça devrait être simple, avec toutes les applications connectées qui existent.
Oui et non.
Chez moi, l&amp;#8217;installation est particulière: mes panneaux solaires sont sur le toit de ma maison, ainsi que les onduleurs et optimiseur.
Ces appareils sont capables de vous donner en direct la production, et mesurent aussi la consommation instantanée, ce qui permet donc de mesurer directement son auto-consommation: on peut savoir si on produit plus qu&amp;#8217;on ne consomme, ou l&amp;#8217;inverse, en temps réel, c&amp;#8217;est parfait non ? Voici par exemple un graphique fournit par SolarEdge en été:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/elec/conso-aout.png&quot; alt=&quot;conso aout&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En rouge, nous avons la consommation.
En vert, la production solaire, et en bleu, l&amp;#8217;autoconsommation.
Vous noterez d&amp;#8217;ores et déja un problème, si, comme moi, vous êtes un tant soit peu curieux: lorsqu&amp;#8217;il y a production solaire, la &lt;em&gt;courbe de consommation&lt;/em&gt; se met à suivre celle de production.
Elle monte lorsque la production augmente et diminue lorsqu&amp;#8217;elle baisse: ça n&amp;#8217;est pas logique et probablement un bug quelque par chez SolarEdge.
J&amp;#8217;ai demandé via mon installateur des explications (ils ne comprennent pas non plus), mais SolarEdge n&amp;#8217;est pas revenu vers eux.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A titre de comparaison, voici un autre graphe ce mois-ci:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/elec/conso-nov.png&quot; alt=&quot;conso nov&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On note déja qu&amp;#8217;il y a des pics de consommation, correspondant à l&amp;#8217;enclenchement de la pompe à chaleur, ou des appareils de cuisson.
On constate aussi que la période de production est plus resserrée, mais qu&amp;#8217;il existe encore, en journée, de la surproduction par moment (ça n&amp;#8217;est pas toujours vrai, dès qu&amp;#8217;il pleut, la production est pour ainsi dire nulle).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si on oublie la fausse valeur de consommation, c&amp;#8217;est parfait me direz-vous !
Et bien oui mais non.
Chez moi, il y a un hic: le capteur de consommation est au niveau de l&amp;#8217;onduleur, près de mon tableau électrique.
Or ici, j&amp;#8217;ai &lt;em&gt;plusieurs&lt;/em&gt; tableaux électriques: un dans mon habitation principale, mais aussi un dans mon garage (bâtiment indépendant) et un autre dans un local technique du jardin.
Lorsque j&amp;#8217;ai acheté cette maison, elle était installée en triphasé, il y avait donc les 3 phases, et de mon compteur EDF principal, dans mon allée, partent des lignes électriques vers 3 bâtiments distincts.
Ces phases étaient particulièrement déséquilibrées, nous avions donc fait repasser en monophasé, mais ce qu&amp;#8217;il faut retenir, c&amp;#8217;est qu&amp;#8217;il aurait fallu que le capteur soit au niveau du compteur électrique, et non dans ma maison, pour qu’on puisse mesurer correctement la consommation en live.
Pour des raisons techniques, il n&amp;#8217;était pas possible de le faire: j&amp;#8217;ai donc une mesure imparfaite de ma consommation, qui ne donne que la consommation de mon habitation principale.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_ma_solution&quot;&gt;Ma solution&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si on résume, je dispose pour l&amp;#8217;instant d&amp;#8217;un outil qui me donne la production (nous verrons plus loin comment l&amp;#8217;obtenir), mais pas la consommation.
Mais mon fournisseur d&amp;#8217;électricité (Total Energies) propose une clé ATOME qui permet de connaître ce que je consomme du réseau en live, clé qui se branche sur le compteur Linky.
Malheureusement, Enedis ne propose pas d&amp;#8217;APIs permettant de connaître sa consommation live, il n&amp;#8217;y a donc pas d&amp;#8217;autre choix que de louer la clé de Total Energies&amp;#8230;&amp;#8203;
J&amp;#8217;ai donc fait l&amp;#8217;acquisition de cette clé, et je dispose donc des 2 mesures dont j&amp;#8217;ai besoin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;la consommation live donnée par ma clé ATOME: attention, il ne s&amp;#8217;agit donc pas de ma consommation totale, mais de ce que j&amp;#8217;ai besoin &lt;em&gt;en plus de ma production&lt;/em&gt;, du réseau EDF&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;la production live donnée par SolarEdge&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il suffit donc de faire la différence entre les 2 pour savoir de quelle marge on dispose, mais je ne peux jamais, en pratique, savoir combien je consomme.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mon idée a donc été d&amp;#8217;utiliser un vieux Rapsberry PI qui traînait dans mon armoire, combiné à un écran e-ink, pour afficher cette production et cette consommation, ainsi qu&amp;#8217;une &quot;note&quot; permettant de suggérer de lancer une machine à laver, par exemple.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai donc fait l&amp;#8217;acquisition de &lt;a href=&quot;https://www.amazon.fr/gp/product/B075FRVC4L/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;cet écran&lt;/a&gt;, un écran e-ink dont la consommation en veille est nulle, ce qui, pour un outil de monitoring de consommation d&amp;#8217;énergie, me semblait le minimum.
Nous verrons cependant que ça ne fut pas sans inconvénients.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_les_apis_toujours_le_point_faible&quot;&gt;Les APIs, toujours le point faible&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bien, maintenant que nous savons que les données sont disponibles, via le &lt;a href=&quot;https://monitoring.solaredge.com&quot;&gt;site de SolarEdge&lt;/a&gt; pour la production, et via l&amp;#8217;application Total Energies pour la clé live, il fallait disposer de ces données via des API que je puisse interroger via mon Raspberry.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Là, douche froide:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SolarEdge propose bien une API pour développeurs, mais elle n&amp;#8217;est ni super bien documentée (il faut comprendre soit-même à quoi correspondent les champs retournés), ni illimitée : on ne peut effectuer que 300 requêtes par jour, soit un peu moins d&amp;#8217;une requête toutes les 5 minutes ! C&amp;#8217;est d&amp;#8217;autant plus regrettable que l&amp;#8217;information est disponible &lt;em&gt;en continu&lt;/em&gt; et en live via leur interface web!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pour Total Energies, c&amp;#8217;est encore pire: il n&amp;#8217;y a pas d&amp;#8217;API officielle. Il faut donc &quot;hacker&quot; pour avoir accès, en simulant une connexion via l&amp;#8217;application, qui donne la consommation live&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, ni SolarEdge, ni Total ne proposent d&amp;#8217;API de type push, ou d&amp;#8217;event bus qu&amp;#8217;on puisse écouter pour obtenir les informations.
C&amp;#8217;est très décevant, à une heure où ce genre d&amp;#8217;optimisations devient critique pour une bonne gestion de notre consommation électrique: c&amp;#8217;est un outil pour le climat !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;autre problème, c&amp;#8217;est que même si j&amp;#8217;utilise l&amp;#8217;API officielle de SolarEdge et que je réussis à récupérer l&amp;#8217;information de Total Energies, ces APIs sont instables : elles tombent très souvent &quot;en panne&quot; et ne renvoient aucune info.
Bref, lorsque ça marche, c&amp;#8217;est parfait, mais souvent, ça ne fonctionne tout simplement pas, par exemple en ce moment, ma production indique 0 alors que ça n&amp;#8217;est pas le cas:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/elec/moniteur-nov.jpg&quot; alt=&quot;moniteur nov&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci me permet au moins de savoir qu&amp;#8217;en ce moment, je demande 1135W du réseau, ce qui signifie que je consomme sensiblement plus (entre le chauffe-eau, l&amp;#8217;ordinateur de mon fils qui joue à Minecraft et la PS5 de mon autre garçon).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_un_peu_de_technique&quot;&gt;Un peu de technique&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors comment récupérer en pratique ces informations ?
En fait j&amp;#8217;ai adapté un script en Python qui, toutes les 5 minutes, se connecte à ces 2 APIs, récupère les informations et déclenche le rafraîchissement de l&amp;#8217;écran.
Alors, Python, personnellement c&amp;#8217;est pas ma tasse de thé.
J&amp;#8217;ai l&amp;#8217;impression de refaire du PHP, avec des scripts cracras et des variables globales de partout.
Il y a sûrement possibilité de faire mieux, mais en bidouille en se connectant par SSH à mon Raspberry, c&amp;#8217;est pour l&amp;#8217;instant tout ce que j&amp;#8217;ai.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Vous trouverez donc le script &lt;a href=&quot;https://gist.github.com/melix/90dce1c44524a368f9186981ec16b475&quot;&gt;ici&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Parmi les problèmes, je vous mentionnait celui du choix de l&amp;#8217;écran.
J&amp;#8217;avoue avoir été relativement naïf, parce qu&amp;#8217;à l’utilisation, si l&amp;#8217;écran e-ink est très sympa à voir, son rafraîchissement prend&amp;#8230;&amp;#8203; jusqu&amp;#8217;à 30s !
En effet, la façon de dessiner sur ces écrans est assez particulière: on écrit des modèles mémoire, puis on envoie des instructions à l&amp;#8217;écran pour effacer telle zone, etc.
Ces instructions sont très lentes à s&amp;#8217;exécuter, mais surtout, elles provoquent systématiquement un effet bizarre à l&amp;#8217;écran, qui passe du blanc au noir plusieurs fois, commence à afficher des choses, puis la couleur, etc&amp;#8230;&amp;#8203;
Bref, pas super sympa pour du &quot;live&quot;, mais, au final, suffisant pour mon usage.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au final, j&amp;#8217;ai quand même un outil proche de ce que je souhaitais.
Il nous a permis, d&amp;#8217;ores et déjà, d&amp;#8217;adapter notre consommation: n&amp;#8217;importe qui peut regarder l&amp;#8217;écran et décider de lancer une machine si la production est importante, alors que cette info n&amp;#8217;était avant uniquement disponible que pour moi, via une application sur mobile: ici, l&amp;#8217;information est donnée en continu, de manière passive, via cet écran.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous avons, par exemple, pu adapter notre consommation en automne: la pompe à chaleur ne fonctionnait pas (pas besoin de chauffer) et donc nous avons pu mettre notre voiture à charger, plus travailler tous les 2 à domicile et lancer une machine à laver, sans consommer un seul kW du réseau EDF ! Lorsque le monitoring a indiqué que nous commencions à consommer du réseau, il a suffit de couper la charge de la voiture (malheureusement, l&amp;#8217;application MyPeugeot est extrêmement limitée et ne permet pas d&amp;#8217;interrompre une charge mais simplement de la différer, mais c&amp;#8217;est un autre problème).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Depuis Juillet, nous sommes à -70% de consommation électrique, ce qui est énorme.
Cependant, les conditions météo ont, jusqu&amp;#8217;ici, été très favorables: beaucoup de soleil et des températures record en Octobre et Novembre (malheureusement pour le climat&amp;#8230;&amp;#8203;).
Depuis une semaine, la pompe à chaleur se met régulièrement en route pour tenir les 19⁰C, mais j&amp;#8217;ai des résultats surprenants:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;90kWh consommés en Novembre pour chauffer l&amp;#8217;eau&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;et seulement 9kWh pour le chauffage !&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;avenir nous dira si le passage à une pompe à chaleur pour le chauffage était une bonne idée ou non (en même temps, ici nous n&amp;#8217;avions pas trop le choix).
Il serait pertinent, compte tenu du surplus de production qui arrive souvent en journée, d&amp;#8217;installer des batteries pour maximiser l&amp;#8217;autoconsommation.
Malheureusement comme je l&amp;#8217;ai indiqué, le prix est à ce jour bien trop élevé.
Je devrais donc me contenter de revendre ma production (au prix de 10cts le kWh, prix fixé pour 20 ans (!!) contre environ 15cts lorsque je consomme).
Attention cependant, lorsqu&amp;#8217;on revend et que notre installation, comme la nôtre, dépasse les 3kWc, alors nous devons déclarer celà en revenus.
Cela rend la revente bien moins intéressante, puisque malgré le fait qu&amp;#8217;on va &quot;consommer&quot; notre surplus, mais à des heures différentes, le tarif de rachat ansi que le fait de devoir déclarer réduit sensiblement la rentabilité.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Hello, Mastodon (goodbye Twitter!)</title>
      <link>https://melix.github.io/blog//2022/11/hello-mastodon.html</link>
      <pubDate>Sun, 6 Nov 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/11/hello-mastodon.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It should be no news to anyone that &lt;a href=&quot;https://www.bbc.com/news/technology-63402338&quot;&gt;Elon Musk finally took control of Twitter&lt;/a&gt;.
There were reasons to be worried about this move, but the &lt;a href=&quot;https://www.reuters.com/technology/twitter-start-layoffs-friday-morning-internal-email-2022-11-04/&quot;&gt;recent events at Twitter made it worse than most of us would have thought&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;TL/DR: I am moving primarily to Mastodon. You can now follow me at &lt;a href=&quot;https://mastodon.xyz/@melix&quot;&gt;@melix@mastodon.xyz&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_twitter_as_a_self_promotion_tool&quot;&gt;Twitter as a self-promotion tool&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lots of people have a complicated story with Twitter, I am no different.
I joined Twitter back in January 2010, and I&amp;#8217;ve grown up to more 4800 followers nowadays, and from time to time, I suffered from being exhausted by the negativity of the network.
Last year, I was even in the middle of an harassment story, because some trolls thought I was someone else.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, Twitter has been my main communication channel for professional work: this is where I explain what I work on, announce software updates, events I will attend or talk to, or publish blog posts links like this one.
This is also my main feedback channel and where I do most of my technology intelligence.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My community of followers doesn&amp;#8217;t make me an &quot;influencer&quot; at large scale, like a rock star, but it definitely had an influence on my professional career.
For example, different potential employers explicitly mentioned my &quot;influence&quot; and social media presence, for example, as a major reason why they&amp;#8217;d like to work with me.
I have no doubt that without Twitter, my career wouldn&amp;#8217;t have been the one it is today.
For that, I am forever grateful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am also using my Twitter account for personal stuff.
Most notably, some of you have seen my astronomy pictures.
You may also have seen some political posts and point of views being expressed.
While I&amp;#8217;m using Twitter professionally, I always made it clear that the opinions I&amp;#8217;m expressing are not representative of my employer&amp;#8217;s point of view.
Said differently, I see my Twitter account as a &lt;em&gt;tool&lt;/em&gt;, but a tool which &quot;survives&quot; my different employers.
To some extent, it&amp;#8217;s part of my digital identity.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_then_came_elon_musk&quot;&gt;Then came Elon Musk&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I was already very critical of Elon Musk, and not just because of the infamous Starlink project, for which I have so much to say.
One can admire what he created with Tesla or SpaceX (and I do admire), but at the same time, we can recognize that he&amp;#8217;s a terrible human being.
This is all about business, all about money, and “freedom of speech” only when it suits his point of view.
Elon is making people work as hard as they can until they burnout or simply get fired once they have &quot;done their job&quot;.
Elon is also a &quot;special&quot; view of free speech, where those who pay will have right for free speech, while those who don&amp;#8217;t won&amp;#8217;t be visible anymore.
He&amp;#8217;s also the one blocking anyone criticizing him.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, the head of Twitter, and therefore Twitter itself, now represents everything I fight against in my personal life.
This is the world I don&amp;#8217;t want for my children.
This is the world which puts money before human beings, the world where power, masculinity, is emphasized.
Elon doesn&amp;#8217;t care that we exhaust resources, as long as part of the population can survive, be it on Mars (!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But now, he fired half of the company, by email, &lt;a href=&quot;https://techcrunch.com/2022/11/04/twitter-faces-a-class-action-lawsuit-over-mass-employee-layoffs-with-proper-legal-notice/&quot;&gt;ignoring the law&lt;/a&gt;, because, you know, Musk does whatever he wants.
It happens that I know people who got fired and I also know folks who used to work for Twitter before.
I, for one, am respectful of what people produce.
I am respectful of what efforts it takes to build a site like Twitter, and, in general, I am someone who puts &lt;em&gt;trust&lt;/em&gt; in other people at the top of my hierarchy of beliefs.
So I find it extremely annoying, or, to be clear, disgusting when someone who has absolutely no understanding of how to build such a large community over the years, decides to layoff half of a company, change the spirit of the website so that paying customers have more power than the others, so that it matches more his political point of view.
Even if the company is losing $4M a day, compared to B44$, seriously, what would have it taken to show the people who built Twitter a bit of respect and simply build a plan, say, of volunteer departures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Elon Musk&amp;#8217;s behavior is everything I hate: someone coming because they have power (understand, money), and then ruining other people lives just because he can, without any respect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This puts me in a difficult situation: at the same time, I &lt;em&gt;need&lt;/em&gt; Twitter, because it&amp;#8217;s a professional tool which can&amp;#8217;t be easily replaced and I &lt;em&gt;have to go&lt;/em&gt; because there&amp;#8217;s no way I&amp;#8217;m going to pay 8 dollars a month to a company who treats human beings like that, and simply to get more visibility over others just because I can afford it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_hello_mastodon&quot;&gt;Hello, Mastodon!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a FOSS supporter, back in 2017, I had registered to &lt;a href=&quot;https://joinmastodon.org&quot;&gt;Mastodon&lt;/a&gt;.
My account was left more or less inactive for years, because, honestly, not many people used it so it was &amp;#8230;&amp;#8203; annoying.
This was like talking in an echo chamber.
Until the rumor of Elon Musk acquiring Twitter started: we&amp;#8217;ve seen more and more people joining, and I&amp;#8217;m super glad that this week alone, &lt;em&gt;many&lt;/em&gt; other people, including from the Tech industry, decided to make the move.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;No more ads. No more recommendations. A clean timeline, as it should be.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s really refreshing to be on Mastodon, it feels like the Twitter from the early days.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, Mastodon has a number of key differences, which make it more &quot;complicated&quot; for users to understand.
First of all, and that&amp;#8217;s the biggest issue for joining, Mastodon is &lt;em&gt;not&lt;/em&gt; a single site like Twitter: it&amp;#8217;s a &lt;em&gt;federation&lt;/em&gt; of servers.
Just like you have a provider for your email (say GMail, Hotmail, etc.), you can choose your Mastodon server provider.
As an OSS project, you can go even as far as hosting your own instance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, Mastodon is, by nature, distributed, which makes it completely immune to what just happened to Twitter.
But it also means that there are a few things you should be aware when you join a server:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;content moderation is the responsibility of the server administrator: they can block you, read your posts, private messages. They can block other providers too, which means, for example, that if you choose to go to an instance which has a Code of Conduct, you have to follow the rules.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the good news is that you &lt;em&gt;own the content&lt;/em&gt;: if you are not happy with your server moderation rules, you can &lt;em&gt;move to a different instance&lt;/em&gt;, and you can move your data with it: toots, folks you follow, followers, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the cost of maintenance is distributed on the community: there are lots of &lt;em&gt;free&lt;/em&gt; servers out there, but you can choose to participate to the bills. You can even build your own server, for a price which wouldn&amp;#8217;t exceed much what Elon wants us to pay to get a blue mark&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hashtags are much more important in Mastodon than Twitter: there&amp;#8217;s no &lt;em&gt;global search&lt;/em&gt;: the only things which are indexed are hash tags. You won&amp;#8217;t find contents which is not with a hash tag.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the internet I remember of.
It&amp;#8217;s not suitable for everyone, but it&amp;#8217;s what I call &lt;em&gt;open&lt;/em&gt;.
What I also like is that it respects freedom of speech, while preserving your freedom of not seeing assholes (there are instances which are full of alt-right folks, but at least, we can block the whole server and not have to suffer their nauseating posts).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, for the time being, I&amp;#8217;m transitioning to Mastodon.
&lt;strong&gt;You can follow me at &lt;a href=&quot;https://mastodon.xyz/@melix&quot;&gt;@melix@mastodon.xyz&lt;/a&gt;&lt;/strong&gt;, and I strongly suggest that you do the same and find a server which suits you.
I will &lt;em&gt;not&lt;/em&gt; support a company which now represents the worst of human beings.
I will &lt;em&gt;not&lt;/em&gt; pay $8 a month to a company which shows no respect to its employees, content creators and business partners.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because it&amp;#8217;s hard to say goodbye to a professional network just like that, I do not plan to shutdown my account on Twitter yet, though: I still didn&amp;#8217;t find a way to solve this cognitive dissonance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So what I plan on doing is moving to Mastodon first.
I have already updated my screen name in Twitter to give a link to my Mastodon account.
I suggest you do the same.
I will now limit my tweets to what is strictly required for my professional career (announcements, etc.).
I will also mostly answer to tweets which are related to moving to Mastodon and use Mastodon for everything else, until I can completely get rid of Twitter.
I am conscious that I may not be able to completely get rid of it, if too many people stay on Twitter.
So be it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Congratulations M. Musk, you ruined Twitter!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Astrophotographie: la suite !</title>
      <link>https://melix.github.io/blog//2022/10/astro-twitch.html</link>
      <pubDate>Wed, 5 Oct 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/10/astro-twitch.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Salut à tous !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je vous avais promis de faire un deuxième live sur Twitch pour parler d&amp;#8217;astrophotographie, cette fois-ci sur la partie logicielle.
J&amp;#8217;ai décidé d&amp;#8217;arrêter de procrastiner et je vous annonce le &lt;strong&gt;mercredi 12 octobre à 20h&lt;/strong&gt; sur &lt;a href=&quot;https://www.twitch.tv/melix_fr&quot;&gt;ma chaîne Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si vous avez raté la première partie sur le matériel astrophoto, c&amp;#8217;est dispo en replay sur &lt;a href=&quot;https://www.youtube.com/watch?v=Hudtta97gDU&quot;&gt;Youtube&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans ce live j&amp;#8217;aborderais comment, à partir des données brutes acquises pendant la nuit, on peut obtenir de belles photos grâce à la magie du logiciel.
Nous parlerons de flats, darks, pré-traitement, stacking, &amp;#8230;&amp;#8203; plein de termes compliqués mais qui au final ne sont pas si difficiles à comprendre.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, il est temps que je prépare tout ça !&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Introducing Micronaut Test Resources</title>
      <link>https://melix.github.io/blog//2022/08/micronaut-test-resources.html</link>
      <pubDate>Thu, 4 Aug 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/08/micronaut-test-resources.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The new &lt;a href=&quot;https://micronaut.io/2022/08/04/micronaut-framework-3-6-0-released&quot;&gt;release of Micronaut 3.6&lt;/a&gt; introduces a new feature which I worked on for the past couple of months, called &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt;.
This feature, which is inspired from &lt;a href=&quot;https://quarkus.io/guides/dev-services&quot;&gt;Quarkus&apos; Dev Services&lt;/a&gt;, will greatly simplify testing of Micronaut applications, both on the JVM and using GraalVM native images.
Let&amp;#8217;s see how.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_test_resources_in_a_nutshell&quot;&gt;Test resources in a nutshell&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; simplifies testing of applications which depend on external resources, by handling the provisioning and lifecycle of such resources automatically.
For example, if your application requires a MySQL server, in order to test the application, you need a MySQL database to be installed and configured, which includes a database name, a username and a password.
In general, those are only relevant for production, where they are fixed.
During development, all you care about is having &lt;em&gt;one&lt;/em&gt; database available.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are a couple of traditional solutions to this problem:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;document that a MySQL server is a pre-requisite, and give instructions about the database to create, credentials, etc. This can be simplified by using Docker containers, but there&amp;#8217;s still manual setup involved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use a library like &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Testcontainers&lt;/a&gt; in order to simplify the setup&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In general, using &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Testcontainers&lt;/a&gt; is preferred, because it integrates well with the JVM and provides an API which can be used in tests to spawn containers and interact with them.
However, a better integration between Micronaut and &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Testcontainers&lt;/a&gt; can improve the developer experience in several ways:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;simplify the container lifecycle configuration by providing an opinionated framework-specific default way, making you think less of how to setup it in the individual tests : tests shouldn&amp;#8217;t need to deal with the container lifecycle: we&amp;#8217;d like to have test containers/resources management as &lt;em&gt;transparent&lt;/em&gt; as possible.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;isolate it better from your application making it simpler to reason about dependencies (and transitive dependencies), not just for the developer, but for example tools enabling native mode as well: Testcontainers APIs &quot;leak&quot; to the test classpath, making it difficult to &lt;a href=&quot;https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html#testing-support&quot;&gt;run tests in native mode&lt;/a&gt;. This is not a problem specific to the Testcontainers library though: many libraries are not yet compatible with GraalVM. Our solution makes it possible to use Testcontainers in native tests without the hassle of configuring it!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;enable support for &quot;development mode&quot;, that is to say when you run the application locally (not the tests, the application itself) or even several distinct projects at once that can benefit from sharing access to the same running containers (for example, an MQTT client and a server may want to use the same container, even if they are individual projects living in distinct Git repositories).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The goal of &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; is to achieve all of these at once:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;zero-configuration&lt;/strong&gt;: without adding any configuration, test resources should be spawned and the application configured to use them. Configuration is only required for advanced use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;classpath isolation&lt;/strong&gt;: use of test resources shouldn&amp;#8217;t leak into your application classpath, nor your test classpath&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;compatible with GraalVM native&lt;/strong&gt;: if you build a native binary, or run tests in native mode, test resources should be available&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;easy to use&lt;/strong&gt;: the Micronaut build plugins for Gradle and Maven should handle the complexity of figuring out the dependencies for you&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;extensible&lt;/strong&gt;: you can implement your own test resources, in case the built-in ones do not cover your use case&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;technology agnostic&lt;/strong&gt;: while lots of test resources use &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Testcontainers&lt;/a&gt; under the hood, you can use any other technology to create resources&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; support advanced development patterns, which are useful in the microservices era.
As an example, it is capable of sharing containers between submodules of a single build, or even between independent projects, from different Git repositories!
Say that you have 2 projects, one built with Gradle, the other with Maven, both needing to communicate using the same message bus: Micronaut is capable of handling this use case for you, making it extremely easy to test components interacting with each other!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because of these constraints, we decided to use &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Testcontainers&lt;/a&gt;, because the library is just perfect for the job, but in an &lt;em&gt;isolated&lt;/em&gt; process instead, as I&amp;#8217;m going to describe below.
Note that this solution is also 100% compatible with &lt;a href=&quot;https://www.testcontainers.cloud/&quot;&gt;Testcontainers Cloud&lt;/a&gt;, which makes container provisioning even easier!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_using_micronaut_test_resources&quot;&gt;Using Micronaut Test Resources&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_enabling_test_resources_support&quot;&gt;Enabling test resources support&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; integrates with build tools.
In both Maven and Gradle, you need to enable test resources support.
If you create a new project using &lt;a href=&quot;https://micronaut.io/launch&quot;&gt;Micronaut Launch&lt;/a&gt; or the Micronaut CLI, test resources will be configured for you, but if you migrate an existing application to test resources, here&amp;#8217;s what you need to do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are using Maven, you will need to upgrade to the Micronaut 3.6 parent POM and add the following property:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;properties&amp;gt;
   &amp;lt;micronaut.test.resources.enabled&amp;gt;true&amp;lt;/micronaut.test.resources.enabled&amp;gt;
&amp;lt;/properties&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For Gradle, you can use test resources with Micronaut 3.5+ and you simply need to use the test resources plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &apos;io.micronaut.application&apos; version &apos;3.5.1&apos;
    id &apos;io.micronaut.test-resources&apos; version &apos;3.5.1&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_our_first_test_resources_contact&quot;&gt;Our first test resources contact&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post we will write an application which makes use of Micronaut Data and connects to a MySQL server to list books.
The whole application code is &lt;a href=&quot;https://github.com/melix/micronaut-test-resources-demo/&quot;&gt;available on GitHub&lt;/a&gt;, so I&amp;#8217;m only going to show the relevant parts for clarity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In such an application, we typically need a repository:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@JdbcRepository(dialect = Dialect.MYSQL)
public interface BookRepository extends CrudRepository&amp;lt;Book, Long&amp;gt; {
    @Override
    List&amp;lt;Book&amp;gt; findAll();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And this repository makes use of the &lt;code&gt;Book&lt;/code&gt; class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@MappedEntity
public class Book {
    @Id
    @GeneratedValue(GeneratedValue.Type.AUTO)
    private Long id;

    private String title;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order for Micronaut to use the database, we need to add some configuration to our &lt;code&gt;application.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;datasources:
  default:
    schema-generate: CREATE
    db-type: mysql&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The most important thing to see is that &lt;strong&gt;we don&amp;#8217;t&lt;/strong&gt; specify any username, password or URL to connect to our database: the only thing we have to specify is the database type of our datasource.
We can then write the following test:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@MicronautTest
class DemoTest {

    @Inject
    BookRepository bookRepository;

    @Test
    @DisplayName(&quot;A MySQL test container is required to run this test&quot;)
    void testItWorks() {
        Book book = new Book();
        book.setTitle(&quot;Yet Another Book &quot; + UUID.randomUUID());
        Book saved = bookRepository.save(book);
        assertNotNull(saved.getId());
        List&amp;lt;Book&amp;gt; books = bookRepository.findAll();
        assertEquals(1, books.size());
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The test creates a new book, stores it in the database, then checks that we get the expected number of books when reading the repository.
Note, again, that we didn&amp;#8217;t have to specify any container whatsoever.
In this blog post I&amp;#8217;m using Gradle, so we can verify the behavior by running:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;./gradlew test&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you will see the following output (cleaned up for clarity of this blog post):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;i.m.testresources.server.Application - A Micronaut Test Resources server is listening on port 46739, started in 128ms
i.m.t.e.TestResourcesResolverLoader - Loaded 2 test resources resolvers: io.micronaut.testresources.mysql.MySQLTestResourceProvider, io.micronaut.testresources.testcontainers.GenericTestContainerProvidereted
o.testcontainers.DockerClientFactory - Connected to docker:
  Server Version: 20.10.17
  API Version: 1.41
  Operating System: Linux Mint 20.3
  Total Memory: 31308 MB
🐳 [testcontainers/ryuk:0.3.3] - Creating container for image: testcontainers/ryuk:0.3.3
🐳 [testcontainers/ryuk:0.3.3] - Container testcontainers/ryuk:0.3.3 is starting: 1f5286fa728aca74a7d6d4c0eb2148a3bc81f5c028027496d7aabda7b7ed45e8
🐳 [testcontainers/ryuk:0.3.3] - Container testcontainers/ryuk:0.3.3 started in PT0.655476S
o.t.utility.RyukResourceReaper - Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
🐳 [mysql:latest] - Creating container for image: mysql:latest
🐳 [mysql:latest] - Container mysql:latest is starting: d796c7a1ce10f393a4181f12967ee77ac9864f45595f97967c700f022e86ac7d
🐳 [mysql:latest] - Waiting for database connection to become available at jdbc:mysql://localhost:49209/test using query &apos;SELECT 1&apos;
🐳 [mysql:latest] - Container is started (JDBC URL: jdbc:mysql://localhost:49209/test)
🐳 [mysql:latest] - Container mysql:latest started in PT7.573915S

BUILD SUCCESSFUL in 11s
7 actionable tasks: 2 executed, 5 up-to-date&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What does this tell us? First, that a &quot;Micronaut Test Resources server&quot; was spawned, for the lifetime of the build.
When the test was executed, this service was used to start a MySQL test container, which was then used during tests.
We didn&amp;#8217;t have to configure anything, test resources did it for us!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_running_the_application&quot;&gt;Running the application&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is also interesting is that this also works if you run the application in development mode.
Using Gradle, you do this by invoking &lt;code&gt;./gradlew run&lt;/code&gt; (&lt;code&gt;mvn mn:run&lt;/code&gt; with Maven): as soon as a bean requires access to the database, a container will be spawned, and automatically shut down when you stop the application.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Of course, in production, there won&amp;#8217;t be any server automatically spawned for you: Micronaut will rely on whatever you have configured, for example in an &lt;code&gt;application-prod.yml&lt;/code&gt; file. In particular, the URL and credentials to use.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is even nicer is that you can use this in combination with Gradle&amp;#8217;s continuous mode!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To illustrate this, let&amp;#8217;s create a controller for our books:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@Controller(&quot;/&quot;)
public class BookController {
    private final BookRepository bookRepository;

    public BookController(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @Get(&quot;/books&quot;)
    public List&amp;lt;Book&amp;gt; list() {
        return bookRepository.findAll();
    }

    @Get(&quot;/books/{id}&quot;)
    public Book get(Long id) {
        return bookRepository.findById(id).orElse(null);
    }

    @Delete(&quot;/books/{id}&quot;)
    public void delete(Long id) {
        bookRepository.deleteById(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now start the application in &lt;em&gt;continuous mode&lt;/em&gt;: &lt;code&gt;./gradlew -t run&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will see that the application starts a container as expected:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;INFO  io.micronaut.runtime.Micronaut - Startup completed in 9166ms. Server Running: http://localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Notice how it took about 10 seconds to start the application, most it it spent in starting the MySQL test container itself.
You definitely don&amp;#8217;t want to pay this price for every change you make, so this is where the continuous mode is helpful.
If we ask for the list of books, we&amp;#8217;ll get an empty list:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ http :8080/books
HTTP/1.1 200 OK
Content-Type: application/json
connection: keep-alive
content-length: 2
date: Tue, 26 Jul 2022 16:59:51 GMT

[]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is expected, but notice how we didn&amp;#8217;t have a method to actually add a book to our store.
Let&amp;#8217;s fix this by editing the &lt;code&gt;BookController.java&lt;/code&gt; class &lt;em&gt;without stopping the server&lt;/em&gt;.
Add the following method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;    @Get(&quot;/books/add/{title}&quot;)
    public Book add(String title) {
        Book book = new Book();
        book.setTitle(title);
        return bookRepository.save(book);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Save the file and notice how Gradle instantly reloads the application, but doesn&amp;#8217;t restart the database: it&amp;#8217;s already there so it&amp;#8217;s going to reuse it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the logs you will see something like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;INFO  io.micronaut.runtime.Micronaut - Startup completed in 1086ms. Server Running: http://localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This time the application started in just a second! Let&amp;#8217;s add a book:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ http :8080/books/add/Micronaut%20in%20action
HTTP/1.1 200 OK
Content-Type: application/json
connection: keep-alive
content-length: 38
date: Tue, 26 Jul 2022 17:03:57 GMT

{
    &quot;id&quot;: 1,
    &quot;title&quot;: &quot;Micronaut in action&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, if we stop the application (by hitting CTRL+C) and start again, you will see that the database will be destroyed when the application shuts down.
Let&amp;#8217;s see how we can &quot;survive&quot; different build invocations.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_keeping_the_service_alive&quot;&gt;Keeping the service alive&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, the test resources service is &lt;em&gt;short lived&lt;/em&gt;: it&amp;#8217;s going to be started at the beginning of a build, and shutdown at the end of a build.
This means, that it will live as long as you have tests running, or, if running in development mode, as long as the application is alive.
However, you can make it survive the build, and reuse the containers in several, independent build invocations.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To do this, you need to &lt;em&gt;explicitly start the test resources service&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;./gradlew startTestResourcesService&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This starts the test resources service in the background: it did &lt;em&gt;not&lt;/em&gt; start our application, nor did it run tests.
This means that now, we can start our application:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;./gradlew run&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And, because it&amp;#8217;s the first time the application is launched since we started the test resources service, it&amp;#8217;s going to spawn a test container:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;INFO  io.micronaut.runtime.Micronaut - Startup completed in 9211ms. Server Running: http://localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can add our book:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ http :8080/books/add/Micronaut%20in%20action
HTTP/1.1 200 OK
Content-Type: application/json
connection: keep-alive
content-length: 38
date: Tue, 26 Jul 2022 17:03:57 GMT

{
    &quot;id&quot;: 1,
    &quot;title&quot;: &quot;Micronaut in action&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The difference is now that if we stop the application (e.g hit CTRL+C) and start it again, it will &lt;em&gt;reuse the container&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;INFO  io.micronaut.runtime.Micronaut - Startup completed in 895ms. Server Running: http://localhost:8080&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If we list our books, the database wasn&amp;#8217;t cleaned, so we&amp;#8217;ll get the book we created from the previous time we started the app:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ http :8080/books
HTTP/1.1 200 OK
Content-Type: application/json
connection: keep-alive
content-length: 40
date: Tue, 26 Jul 2022 17:14:40 GMT

[
    {
        &quot;id&quot;: 1,
        &quot;title&quot;: &quot;Micronaut in action&quot;
    }
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nice, right?
However there&amp;#8217;s a gotcha if you do this: what happens if we run tests?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew test

&amp;gt; Task :compileTestJava
Note: Creating bean classes for 1 type elements

&amp;gt; Task :test FAILED

DemoTest &amp;gt; A MySQL test container is required to run this test FAILED
    org.opentest4j.AssertionFailedError at DemoTest.java:28&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Why is that? This is simply because our tests expect a &lt;em&gt;clean&lt;/em&gt; database, and we had a book in it, so keep this in mind if you&amp;#8217;re using this mode.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At some point, you will want to close all open resources.
You can do this by explicitly stopping the test resources service:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;./gradlew stopTestResourcesService&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, you can run the tests again and see them pass:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew test

...
INFO  🐳 [testcontainers/ryuk:0.3.3] - Creating container for image: testcontainers/ryuk:0.3.3
INFO  🐳 [testcontainers/ryuk:0.3.3] - Container testcontainers/ryuk:0.3.3 is starting: ea2aa1c7f1e66a9c7306b00443e8a6693451f3f02bd780b3e2ed7b96ed59936a
INFO  🐳 [testcontainers/ryuk:0.3.3] - Container testcontainers/ryuk:0.3.3 started in PT0.553559699S
INFO  o.t.utility.RyukResourceReaper - Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
INFO  o.testcontainers.DockerClientFactory - Checking the system...
INFO  o.testcontainers.DockerClientFactory - ✔︎ Docker server version should be at least 1.6.0
INFO  🐳 [mysql:latest] - Creating container for image: mysql:latest
INFO  🐳 [mysql:latest] - Container mysql:latest is starting: 1c6437a55b8f9e5668bcec4aef27087c889b8a77ca18d2ddf58809853482a422
INFO  🐳 [mysql:latest] - Waiting for database connection to become available at jdbc:mysql://localhost:49227/test using query &apos;SELECT 1&apos;
INFO  🐳 [mysql:latest] - Container is started (JDBC URL: jdbc:mysql://localhost:49227/test)
INFO  🐳 [mysql:latest] - Container mysql:latest started in PT7.469460173S

BUILD SUCCESSFUL in 11s
7 actionable tasks: 2 executed, 5 up-to-date&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_native_testing&quot;&gt;Native testing&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Did you know that you can run your test suite in native mode?
That is to say, that the test suite is going to be compiled into a native binary which runs tests?
One issue with this approach is that it&amp;#8217;s extremely complicated to make it work with Testcontainers, as it requires additional configuration.
With &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt;, there is no such problem: you can simply invoke &lt;code&gt;./gradlew nativeTest&lt;/code&gt; and the tests will properly run.
This works because Testcontainers libraries do not leak into your test classpath: the process which is responsible for managing the lifecycle of test resources is isolated from your tests!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_under_the_hood&quot;&gt;Under the hood&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_how_does_that_work&quot;&gt;How does that work?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, Micronaut is capable of reacting to the &lt;em&gt;absence&lt;/em&gt; of a configured property.
For example, a datasource, in order to be created, would need the value of the &lt;code&gt;datasources.default.url&lt;/code&gt; property to be set.
&lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; work by &lt;em&gt;injecting&lt;/em&gt; those properties at runtime: when the property is read, it triggers the creation of test resources.
For example, we can start a MySQL server, then inject the value of the JDBC url to the &lt;code&gt;datasources.default.url&lt;/code&gt; property.
This means that in order for test resources to work, you need to &lt;em&gt;remove&lt;/em&gt; configuration (note that for production, you will need to provide an additional configuration file, for example &lt;code&gt;application-prod.yml&lt;/code&gt;, which provides the actual values).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The entity which is responsible for resolving missing properties is the &quot;Test Resources Server&quot;: it&amp;#8217;s a long lived process which is independent from your application and it is responsible for managing the lifecycle of test resources.
Because it&amp;#8217;s independent from the application, it means it can contain dependencies which are not required in your application such as, typically, the Testcontainers runtime.
But it may also contain additional classes, like JDBC drivers, or even your custom test resources resolver!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because this test resources server is a separate process, it also means it can be shared by different applications, which is the reason why we can share the same containers between independent projects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once you understand that &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; work by resolving &lt;em&gt;missing&lt;/em&gt; properties, it becomes straightforward to configure.
In particular, we offer configuration which makes it very easy to support scenarios which are not supported out of the box.
For example, &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; supports several JDBC or reactive databases (MySQL, PostgreSQL, MariaDB, SQL Server and Oracle XE), Kafka, Neo4j, MQTT, RabbitMQ, Redis, Hashicorp Vault and ElasticSearch, but what if you need a different container?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In that case, &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; offer a conventional way to create such containers, by simply adding some configuration lines: in the documentation &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/#modules-testcontainers&quot;&gt;we demonstrate how to use the &lt;code&gt;fakesmtp&lt;/code&gt; SMTP server with Micronaut Email&lt;/a&gt; for example.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_custom_test_resources&quot;&gt;Custom test resources&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If the configuration-based support isn&amp;#8217;t sufficient, you also have, in addition, the ability to write your own test resources.
If you use Gradle, which I of course recommend, this is made extremely easy by the test resources plugin, which creates an additional source set for this, named &lt;code&gt;testResources&lt;/code&gt;.
For Maven, you would have to create an independent project manually to support this scenario.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an illustration, let&amp;#8217;s imagine that we have a bean which reads a configuration property:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@Singleton
public class Greeter {
     private final String name;

     public Greeter(@Value(&quot;${my.user.name}&quot;) String name) {
         this.name = name;
     }

     public String getGreeting() {
     	return &quot;Hello, &quot; + name + &quot;!&quot;;
     }

     public void sayHello() {
         System.out.println(getGreeting());
     }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This bean requires the &lt;code&gt;my.user.name&lt;/code&gt; property to be set.
We could of course set it in an &lt;code&gt;application-test.yml&lt;/code&gt; file, but for the sake of the exercise, let&amp;#8217;s imagine that this value is &lt;em&gt;dynamic&lt;/em&gt; and needs to be read from an external service.
We will implement a &lt;em&gt;custom test resources resolver&lt;/em&gt; for this purpose.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s create the &lt;code&gt;src/testResources/java/demo/MyTestResource.java&lt;/code&gt; file with the following contents:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;package demo;

import io.micronaut.testresources.core.TestResourcesResolver;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class MyTestResource implements TestResourcesResolver {

    public static final String MY_TEST_PROPERTY = &quot;my.user.name&quot;;

    @Override
    public List&amp;lt;String&amp;gt; getResolvableProperties(Map&amp;lt;String, Collection&amp;lt;String&amp;gt;&amp;gt; propertyEntries, Map&amp;lt;String, Object&amp;gt; testResourcesConfig) {
        return Collections.singletonList(MY_TEST_PROPERTY); // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
    }

    @Override
    public Optional&amp;lt;String&amp;gt; resolve(String propertyName, Map&amp;lt;String, Object&amp;gt; properties, Map&amp;lt;String, Object&amp;gt; testResourcesConfiguration) {
        if (MY_TEST_PROPERTY.equals(propertyName)) {
            return Optional.of(&quot;world&quot;);                    // &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;
        }
        return Optional.empty();
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Tells that this resolver can resolve the &lt;code&gt;my.user.name&lt;/code&gt; property&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Returns the value of the &lt;code&gt;my.user.name&lt;/code&gt; property&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And in order for the resolver to be discovered, we need to create the &lt;code&gt;src/testResources/resources/META-INF/services/io.micronaut.testresources.core.TestResourcesResolver&lt;/code&gt; file with the following contents:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;demo.MyTestResource&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s write a test for this by adding the &lt;code&gt;src/test/java/demo/GreeterTest.java&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;package demo;

import io.micronaut.context.annotation.Requires;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@MicronautTest
class GreeterTest {

    @Inject
    Greeter greeter;


    @Test
    @DisplayName(&quot;Says hello&quot;)
    void saysHello() {
        greeter.sayHello();
        Assertions.assertEquals(&quot;Hello, world!&quot;, greeter.getGreeting());
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now if you run &lt;code&gt;./gradlew test&lt;/code&gt;, you will notice that Gradle will compile your custom test resource resolver, and when the test starts, you will read the following line:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;Loaded 3 test resources resolvers: demo.MyTestResource, io.micronaut.testresources.mysql.MySQLTestResourceProvider, io.micronaut.testresources.testcontainers.GenericTestContainerProvider&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So when the &lt;code&gt;Greeter&lt;/code&gt; bean is created, it will read the value of the &lt;code&gt;my.user.name&lt;/code&gt; property by calling your custom test resolver!
Of course this is a very simple example, and I recommend that you take a look at the &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-test-resources&quot;&gt;Micronaut Test Resources sources&lt;/a&gt; for more examples of implementing resolvers.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, we&amp;#8217;ve explored the new &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; module, which will greatly simplify development of Micronaut applications which depend on external services like databases or messaging queues.
It works by &lt;em&gt;simplifying&lt;/em&gt; configuration, by removing lines which used to be present, but now are dynamically resolved, like &lt;code&gt;datasources.default.url&lt;/code&gt;.
Test resources are handled in a separate process, the test resources server, which is responsible for handling their lifecycle.
This also makes it possible to share the resources (containers, databases, &amp;#8230;&amp;#8203;) between independent builds.
For advanced use cases, &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; provides &lt;em&gt;configuration based&lt;/em&gt; resources creation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, &lt;a href=&quot;https://micronaut-projects.github.io/micronaut-test-resources/latest/guide/&quot;&gt;Micronaut Test Resources&lt;/a&gt; is an extensible framework which will let you implement your own test resources in case the built-in ones miss a feature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Special thanks to &lt;a href=&quot;https://twitter.com/tim_yates/&quot;&gt;Tim Yates&lt;/a&gt; for his hard work on upgrading the Micronaut Guides to use test resources, and &lt;a href=&quot;https://twitter.com/alvaro_sanchez&quot;&gt;Álvaro Sanchez-Mariscal&lt;/a&gt; for his support on the Maven plugin!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Je suis le gars chiant</title>
      <link>https://melix.github.io/blog//2022/07/je-suis-le-gars-chiant.html</link>
      <pubDate>Thu, 28 Jul 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/07/je-suis-le-gars-chiant.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La science. Si j&amp;#8217;avais eu les capacités pour comprendre les abstractions mathématiques nécessaires (j&amp;#8217;essaie encore, de temps en temps), je serais, peut-être, aujourd&amp;#8217;hui assis dans un laboratoire de recherche en astrophysique. J&amp;#8217;ai toujours trouvé fascinant la capacité à émettre des hypothèses, puis les vérifier expérimentalement, pour en faire des théories, théories qui, constamment, peuvent être remises en cause lorsque de nouvelles observations les contredisent. Je suis assis derrière un bureau, mais dans le développement informatique. Ma passion, mon loisir, c&amp;#8217;est l&amp;#8217;astronomie.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_alors_oui_mais_non&quot;&gt;Alors oui, mais non&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai grandi dans un monde empli de graphologie, de magnétisme, d&amp;#8217;ufologie, de pyramidologie, d&amp;#8217;expériences de mort imminente, qui m&amp;#8217;ont aussi profondément marqué. J&amp;#8217;ai entendu des témoignages, j&amp;#8217;ai constaté des guérisons, j&amp;#8217;ai &lt;em&gt;cru&lt;/em&gt; à des beaucoup de choses. Mais pendant une grande partie de mon enfance, je n&amp;#8217;avais pas le bagage intellectuel suffisant pour &lt;em&gt;comprendre&lt;/em&gt;. En un mot, ma fascination pour les sciences se mélait allègrement à celle pour les pseudo-sciences. Parce que j&amp;#8217;ai toujours cherché des explications, j&amp;#8217;en suis revenu et je pense que cette expérience a renforcé mon sens critique si tant est que je me sens, de nos jours, extrêmement proche du mouvement &lt;a href=&quot;https://fr.wikipedia.org/wiki/Z%C3%A9t%C3%A9tique&quot;&gt;zététique&lt;/a&gt; et combats fermement l&amp;#8217;anti-science.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En soirée, je suis le gars chiant qui ne supporte pas qu&amp;#8217;on introduise du surnaturel là où il existe des explications rationnelles, celui qui soulève un sourcil amusé lorsqu&amp;#8217;on lui parle de &lt;a href=&quot;https://fr.wikipedia.org/wiki/S%C5%93urs_Fox&quot;&gt;séances de spiritisme&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Celui qui vous explique que &lt;a href=&quot;https://www.lequotidiendumedecin.fr/archives/pr-edzard-ernst-si-lhomeopathie-est-presentee-comme-une-panacee-il-faudra-quelle-prouve-son&quot;&gt;l&amp;#8217;homéopathie ne fonctionne pas&lt;/a&gt; et qui vous rappelle que s&amp;#8217;il &lt;a href=&quot;https://www.monvoisin.xyz/wp-content/uploads/2020/07/Monvoisin-Pinsault-Diplo-avril19_p21.pdf&quot;&gt;existe un effet placébo, il est moralement discutable de le rembourser&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis le gars chiant qui, il y a déja des années, avertissait mes amis sur la montée du &lt;a href=&quot;https://www.ladn.eu/nouveaux-usages/antivax-histoire-mouvement/&quot;&gt;mouvement antivax&lt;/a&gt;.
Je suis le gars chiant qui, en tant qu&amp;#8217;astronome amateur, vous démontre que &lt;a href=&quot;https://www.afis.org/L-astrologie-a-l-epreuve-ca-ne-marche-pas-ca-n-a-jamais-marche&quot;&gt;l&amp;#8217;astrologie n&amp;#8217;a aucun sens&lt;/a&gt;.
Je suis le gars chiant qui s&amp;#8217;indigne qu&amp;#8217;on puisse vous vendre des absurdités comme des colliers en ambre pour les douleurs dentaires des bébés ou des &lt;a href=&quot;https://menace-theoriste.fr/lithotherapie-1/&quot;&gt;pierres à recharger sous la lumière de la lune&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis le gars chiant qui vous invite à douter de la médecine chinoise, responsable du &lt;a href=&quot;https://dragondubled.fr/medecine-chinoise/rhinoceros-medecine-chinoise/&quot;&gt;massacre des rhinocéros&lt;/a&gt; et de la &lt;a href=&quot;https://fr.wikipedia.org/wiki/Bile_d%27ours&quot;&gt;maltraitance d&amp;#8217;ours&lt;/a&gt; pour des produits dont il est démontré qu&amp;#8217;il n&amp;#8217;ont aucun effet.
Je suis le gars chiant qui, lorsqu&amp;#8217;on lui parle de produits naturels, vous rappelle que &lt;a href=&quot;https://fr.wikipedia.org/wiki/Appel_%C3%A0_la_nature&quot;&gt;naturel ne veut pas nécessairement dire bon pour la santé&lt;/a&gt;.
Je suis le gars chiant qui vous explique que si les électrosensibles sont réellement malades, &lt;a href=&quot;https://www.contrepoints.org/2021/11/22/227498-electrosensibilite-la-maladie-imaginaire-du-xxieme-siecle&quot;&gt;ça n&amp;#8217;est pas à cause des ondes mais de mécanismes psychologiques proches des phobies&lt;/a&gt;.
Je suis le gars chiant qui s&amp;#8217;insurge contre &lt;a href=&quot;https://www.radiofrance.fr/franceinter/podcasts/antidote/antidote-du-vendredi-22-octobre-2021-5726804&quot;&gt;la naturopathie et ses tendances complotistes&lt;/a&gt; et invite à prendre connaissance &lt;a href=&quot;https://www.la-croix.com/Famille/Ecole-meditation-pleine-conscience-accusee-derive-sectaire-2022-02-14-1201200267&quot;&gt;des dérives sectaires de la méditation pleine conscience&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis le gars chiant qui se dit écolo, mais aussi pro-nucléaire: je suis effondré lorsque les &lt;a href=&quot;https://www.latribune.fr/economie/union-europeenne/l-allemagne-pourrait-prolonger-des-centrales-a-charbon-pour-reduire-sa-dependance-au-gaz-russe-906817.html&quot;&gt;écolos incitent à relancer des centrales à charbon&lt;/a&gt; alors que &lt;a href=&quot;https://bonpote.com/nouveau-rapport-du-giec-agir-coutera-moins-cher-que-le-business-as-usual/&quot;&gt;les rapports du GIEC nous disent que chaque tonne de CO2 compte&lt;/a&gt;.
Je suis le gars chiant qui choque ses amis écolos lorsqu&amp;#8217;il affirme que &lt;a href=&quot;https://doseequivalentbanana.home.blog/2021/05/08/dechets-8-on-ne-sait-pas-gerer-les-dechets-nucleaires/&quot;&gt;le stockage géologique des déchets nucléaire n&amp;#8217;est pas un problème pour les générations futures&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je me sens écologiste et je suis convaincu que nous devons aller vers la sobriété: je recherche des modes de vie alternatifs, moins impactants pour l&amp;#8217;environnement, moins industriels et à ce titre j&amp;#8217;ai été attiré par les concepts des &lt;a href=&quot;https://fr.wikipedia.org/wiki/Mouvement_Colibris&quot;&gt;colibris&lt;/a&gt; et ses nombreuses variantes.
Mais je vérifie, je confronte mes croyances. Je suis le gars chiant qui découvre que presque tous les mouvements écologistes sont infiltrés par des groupes anti-science, au premier rang desquels on trouve la &lt;a href=&quot;https://blogs.mediapart.fr/mathieu-repiquet/blog/090520/qu-est-ce-que-l-anthroposophie-entretien-avec-gregoire-perra&quot;&gt;secte anthroposophique&lt;/a&gt;. Je suis le gars chiant qui vous fait remarquer que &lt;a href=&quot;https://www.reussir.fr/ce-celebre-youtubeur-radicalement-change-sa-vision-de-lagriculture&quot;&gt;la permaculture ne permet pas d&amp;#8217;être auto-suffisant&lt;/a&gt;, que la plupart de ces mouvements dits alternatifs ne survivent que grâce à des &quot;formations&quot; qui s&amp;#8217;auto-entretiennent et/ou financent des sectes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis l&amp;#8217;écolo qui vous déculpabilise de ne pas &lt;a href=&quot;https://www.youtube.com/watch?v=rtG77t9kshE&quot;&gt;effacer vos emails car celà ne réduira pas votre emprunte carbone&lt;/a&gt;, mais en profite pour vous faire remarquer que ne pas utiliser votre sèche-linge, oui.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis le gars chiant qui s&amp;#8217;inquiète lorsque des proches suivent des formations de développement personnel ou aux &lt;a href=&quot;https://fr.wikipedia.org/wiki/Enn%C3%A9agramme&quot;&gt;ennéagrammes&lt;/a&gt;, parce qu&amp;#8217;il cherche &lt;a href=&quot;https://www.unadfi.org/actualites/domaines-dinfiltration/sante-et-bien-etre/psychotherapie-et-developpement-personnel/alerte-sur-les-formations-a-l-enneagramme/&quot;&gt;qui sont ceux derrière ces mouvements&lt;/a&gt; et se rend compte qu&amp;#8217;il est très facile de tomber dans des dérives sectaires et ne pas s&amp;#8217;en rendre compte.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis aussi le gars chiant qui fait confiance aux autorités sanitaires, y compris quand elles concluent qu&amp;#8217;&lt;a href=&quot;https://france3-regions.francetvinfo.fr/pays-de-la-loire/loire-atlantique/nantes/cancers-pediatriques-du-pays-de-retz-retour-sur-six-annees-de-combat-1990363.html&quot;&gt;il n&amp;#8217;y a statistiquement pas de surnombre de cancers pédiatriques au Sud de Nantes&lt;/a&gt; alors qu&amp;#8217;on était en &lt;a href=&quot;https://www.ouest-france.fr/pays-de-la-loire/sainte-pazanne-44680/cancers-pediatriques-un-22-sup-e-sup-cas-confirme-autour-de-sainte-pazanne-da95a8e2-f7fc-11ea-86be-f690571173ca&quot;&gt;droit de s&amp;#8217;inquiéter&lt;/a&gt;, mais aussi prêt à revoir ma position si de nouvelles données étaient disponibles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis celui qui heurte la sensibilité de ses amis, les choque, les énerve parfois (souvent), parce que j&amp;#8217;apparais comme ne croyant en rien.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_triste_vie_que_celle_de_celui_qui_ne_croît_en_rien&quot;&gt;Triste vie que celle de celui qui ne croît en rien&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Est-ce vrai ? Est-ce que je ne crois réellement en rien ?
Bien évidemment non.
J&amp;#8217;ai mes propres croyances.
Par exemple, je &lt;em&gt;crois&lt;/em&gt; qu&amp;#8217;il existe une vie extra-terrestre. Sous quelle forme, je n&amp;#8217;en sais rien, mais j&amp;#8217;en suis intimement convaincu. Mais il s&amp;#8217;agit d&amp;#8217;une croyance, et en tant que tel, je n&amp;#8217;essaierai pas de vous l&amp;#8217;imposer. Je peux vous donner des idées sur le &lt;em&gt;pourquoi&lt;/em&gt; j&amp;#8217;y crois, mais il n&amp;#8217;existe aucune &lt;em&gt;preuve&lt;/em&gt;.
J&amp;#8217;ai cru à beaucoup de choses aussi: gamin j&amp;#8217;ai cru au bisou magique, j&amp;#8217;ai cru au Père Noël, j&amp;#8217;ai cru que la graphologie fonctionnait (alors que je suis horrifié de constater que cet outil est toujours utilisé de nos jours !).
Je crois qu&amp;#8217;il n&amp;#8217;existe pas de vie après la mort, mais je ne peux pas vous en apporter la preuve.
Je crois aussi qu&amp;#8217;on n&amp;#8217;a pas besoin de revenir 200 ans en arrière en agriculture pour &quot;sauver la planète&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors on pourrait dire &quot;mais c&amp;#8217;est pas bien grave&quot;, &quot;mais les plantes c&amp;#8217;est quand même bien, c&amp;#8217;est mieux que les produits chimiques&quot;, &quot;la science n&amp;#8217;explique pas tout&quot;, &quot;faut il se fâcher pour ça ?&quot;.
Tant de lieux communs, qui n&amp;#8217;apportent rien, mais qui, en revanche, cachent de tristes réalités: &lt;a href=&quot;https://www.leparisien.fr/faits-divers/miguel-b-le-naturopathe-qui-pretend-guerir-le-cancer-aurait-fait-au-moins-deux-autres-victimes-14-10-2021-XMQKFRJHGFFDLJQRZZ4DWW4E5E.php&quot;&gt;des morts&lt;/a&gt;, souvent &lt;a href=&quot;https://www.midilibre.fr/2021/11/23/covid-19-quest-ce-que-lanthroposophie-possible-frein-a-la-vaccination-dans-les-pays-germanophones-9945410.php&quot;&gt;par milliers&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_dur_dêtre_celui_qui_gâche_la_fête&quot;&gt;Dur d&amp;#8217;être celui qui gâche la fête&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors je si je suis suis le gars chiant, je ne cache pas que c&amp;#8217;est parfois fatigant, moralement: si j&amp;#8217;écris ce billet, c&amp;#8217;est aussi pour exprimer cette fatigue.
C&amp;#8217;est fatigant parce que je vais contre les idées reçues, je &quot;casse l&amp;#8217;ambiance&quot; mais surtout je peux me fâcher avec des personnes que j&amp;#8217;apprécie énormément.
C&amp;#8217;est fatigant parce qu&amp;#8217;on me regarde en sachant d&amp;#8217;avance que je vais intervenir, mais on ne croira pas ce que je dis, même preuves à l&amp;#8217;appui.
C&amp;#8217;est fatigant parce que je constate la montée de l&amp;#8217;obscurantisme, du complotisme et que je me sens impuissant.
C&amp;#8217;est fatigant parce qu&amp;#8217;il est urgent d&amp;#8217;agir pour sauver notre avenir (je ne parlerai pas de sauver la planète, c&amp;#8217;est l&amp;#8217;espèce humaine, et les espèces actuelles en général qui est en jeu) et que les décisions prises ne sont pas à la hauteur.
C&amp;#8217;est fatigant parce que j&amp;#8217;aspire à plus d&amp;#8217;écologie, plus de simplicité, mais que tous les mouvements que je trouve sont plombés par de l&amp;#8217;anti-science et des sectes déguisées en &quot;spiritualité&quot;.
C&amp;#8217;est fatigant parce qu&amp;#8217;on me caricature: je suis le &quot;rationnel&quot; qui ne comprend rien aux sciences humaines ou à l&amp;#8217;humain en général.
C&amp;#8217;est fatigant parce qu&amp;#8217;on se bat constamment contre l&amp;#8217;intolérance.
Tout ce que je vous raconte est présent partout: famille, amis, collègues, politiques, mais chez moi y compris.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, parfois, parce que je ne veux pas me fâcher ou faire honte à madame, je me tais et je deviens d&amp;#8217;humeur sombre, ne m&amp;#8217;en voulez pas.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous sommes tous pleins de croyances: la question est de savoir si nous sommes prêts à les remettre en question, pour le bien de tous, et si ces croyances doivent influencer les décisions que nous prenons pour la communauté.
Et parce que nous sommes tous susceptibles de faire des erreurs, je ne porte aucun jugement moral à celles et ceux qui croient ceci ou celà: nous sommes tous pleins de contradictions et je ne suis pas mieux qu&amp;#8217;un autre.
Je n&amp;#8217;en veux pas à ceux qui croient, je ne doute pas qu&amp;#8217;ils aient de bonnes intentions.
Je pourrais en vouloir à ceux qui continuent de croire lorsqu&amp;#8217;on leur montre qu&amp;#8217;il y a de quoi douter, ou mieux qu&amp;#8217;on leur apporte des preuves, mais &lt;a href=&quot;https://fr.wikipedia.org/wiki/Biais_cognitif&quot;&gt;notre cerveau est câblé pour rendre la remise en question difficile&lt;/a&gt;.
J&amp;#8217;en veux, en revanche, à ceux qui utilisent &lt;em&gt;sciemment&lt;/em&gt; l&amp;#8217;ignorance des gens pour en tirer profit financièrement ou pour psychologiquement de personnes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je n&amp;#8217;ai pas de chiffres à vous donner, mais &lt;em&gt;je crois&lt;/em&gt; que ces ordures sont nombreuses.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>There is no single dependency graph</title>
      <link>https://melix.github.io/blog//2022/07/there-is-no-single-dependency-graph.html</link>
      <pubDate>Mon, 4 Jul 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/07/there-is-no-single-dependency-graph.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What are the dependencies of Micronaut?
While the question may seem obvious, the answer is not.
I realized, over the years, that many developers tend to ignore the complexity of dependency management in the Java ecosystem.
In particular, I faced several occasions when discussing dependency upgrades (in particular in the context of security updates) when it became obvious that there was a big gap between the mental model that some people have, and the reality.
In this blog post I want to address some misconceptions around dependencies in the Java ecosystem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_libraries_vs_applications&quot;&gt;Libraries vs applications&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_applications_are_easier&quot;&gt;Applications are easier&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First and foremost, we have to make a difference between a &lt;em&gt;library&lt;/em&gt; and an &lt;em&gt;application&lt;/em&gt;.
If I install, say, a desktop application, then the notion of &quot;dependencies of the application&quot; seem quite obvious: they are often bundled with the application in a &lt;code&gt;libs&lt;/code&gt; directory, so all we have to do is look into that.
Therefore, the question &quot;what are the dependencies of X&quot; can be conflated to a simpler question: &quot;what are the dependencies that application X requires at runtime to run properly&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is already a simplfication, though: nothing prevents the application from using a plugin system.
This would make the answer to that question more complicated, but let&amp;#8217;s focus on the simplest case.
Because we have that file list at hand, answering questions like &quot;is X vulnerable to log4shell&quot; is easy: we can look into the &lt;code&gt;libs&lt;/code&gt; directory, and if we find a vulnerable version of log4j in there, then we know for sure if the application uses a vulnerable dependency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This model, the &quot;Windows installer&quot; one, is what lots of developers have in mind.
The problem is often that they assume that the &lt;em&gt;libraries&lt;/em&gt; work the same, but they don&amp;#8217;t.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_library_dependencies&quot;&gt;Library dependencies&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For libraries (and frameworks, which can be seen as &quot;super libraries&quot;) the answer is indeed more complex.
A library is intended to be consumed by an application, or another library.
Therefore, when we ask the question &quot;what are the dependencies of library L&quot;, then the answer is &quot;it depends&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, libraries will introduce us to the world of &lt;em&gt;transitive dependencies&lt;/em&gt;: an application will depend on libraries, which themselves have dependencies on other libraries.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, you can have the following dependency graph:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/simple-dependency-graph.svg&quot; alt=&quot;simple dependency graph&quot; width=&quot;178&quot; height=&quot;345&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can already see that we have a pelicular situation, where 2 libraries depend on the same module &lt;code&gt;c&lt;/code&gt;.
If they require the same version of &lt;code&gt;c&lt;/code&gt;, then we are lucky.
If they don&amp;#8217;t, then we run in a situation called a &lt;em&gt;version conflict&lt;/em&gt;, where different tools will use different strategies to solve them (no, Maven and Gradle, in particular, don&amp;#8217;t have the same way of dealing with dependency conflicts).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Say that &lt;code&gt;a&lt;/code&gt; requires &lt;code&gt;c 1.0&lt;/code&gt; and that &lt;code&gt;d&lt;/code&gt; requires &lt;code&gt;c 1.1&lt;/code&gt;: a reasonable strategy is to do &lt;em&gt;optimistic upgrades&lt;/em&gt; and to choose &lt;code&gt;c 1.1&lt;/code&gt; because it&amp;#8217;s the highest version.
This is the default strategy that Gradle uses, for example.
Maven, on the other hand, takes a simpler, but non prectictable strategy of &quot;closest first&quot;, where &quot;closest&quot; actually means &quot;first seen wins&quot;.
In other words, if &lt;code&gt;a&lt;/code&gt; is seen first, then &lt;code&gt;c 1.0&lt;/code&gt; will be used.
Reverse the order of dependencies and &lt;code&gt;c&lt;/code&gt; will use version &lt;code&gt;1.1&lt;/code&gt;.
Gradle&amp;#8217;s strategy is immune to those problems, but we can already see that there can be a difference between the dependencies which are &lt;em&gt;declared in a build file&lt;/em&gt; and the ones which will &lt;em&gt;effectively be used&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, &lt;strong&gt;it&amp;#8217;s a mistake to look at the declared dependencies to determine what are the effective dependencies of a project&lt;/strong&gt;.
You must always look at the resolved dependency graphs.
This is why I wrote, a few months ago, that &lt;a href=&quot;http://localhost:8820/blog/2020/10/about-dependabot.html&quot;&gt;Dependabot gave a false sense of security&lt;/a&gt; (hopefully, now, they provide &lt;a href=&quot;https://github.blog/2022-07-01-extend-your-dependency-information-in-the-github-dependency-graph-with-new-github-actions/&quot;&gt;an API which can be used to mitigate that problem&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_building_from_sources&quot;&gt;Building from sources&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that we understand that the declared dependencies can be different from the &lt;em&gt;resolved&lt;/em&gt; dependencies, and that we reckon that it&amp;#8217;s the build tool&amp;#8217;s responsibility to solve those conflicts, let&amp;#8217;s address an elephant in the room: building a proejct &lt;em&gt;entirely&lt;/em&gt; from sources (including transitive dependencies).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s imagine that, for legal reasons, you don&amp;#8217;t want to use Maven Central.
Instead you want to build your project against the &lt;em&gt;sources&lt;/em&gt; of your dependencies and build themselves from dependencies, and so on.
Obviously, if your build tool doesn&amp;#8217;t support resolving a dependency graph first (which implies having metadata available for transitive dependencies in some form) &lt;em&gt;then&lt;/em&gt; replacing the dependencies with their sources instead of the binaries, then you have a problem: you&amp;#8217;re going to have to figure out yourself what libraries to build, in which versions, and do everything by hand.
Spoiler alert: no build tool supports that (in the Java ecosystem, some ecosystems like Rust &lt;em&gt;always&lt;/em&gt; use source dependencies, which come with a number of other issues I won&amp;#8217;t address in this blog post).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that in order to build your project, you must:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;resolve all dependencies, including transitive dependencies, to figure out what &lt;em&gt;version&lt;/em&gt; they need&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;find a way to fetch the sources for the particular version of each dependency that is used&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;update the build scripts of that project to use &lt;em&gt;source dependencies&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compile each project independently, and recurse to 1.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But hey, don&amp;#8217;t you see the problem already (except from the fact you&amp;#8217;d have to rewrite all build files, and figure out how to build each project according to their CI specification)?
Because resolved dependency graphs only depend on the &lt;em&gt;top level&lt;/em&gt; project being compiled, you have absolutely no guarantee that you&amp;#8217;ll use the same, resolved versions everywhere.
In the dependency graph above, if you resolve the dependency graph for &lt;code&gt;app&lt;/code&gt;, then you will determine that you need to build &lt;code&gt;c&lt;/code&gt; in version &lt;code&gt;1.1&lt;/code&gt; from sources.
Alright, but to build &lt;code&gt;a&lt;/code&gt;, we will need to build &lt;code&gt;c&lt;/code&gt;&amp;#8230;&amp;#8203; with version &lt;code&gt;1.0&lt;/code&gt;!
In other words, there&amp;#8217;s no way you can &lt;em&gt;consistently&lt;/em&gt; build such a dependency graph from source without having a &lt;em&gt;single, globally resolved&lt;/em&gt; dependency graph, and a &lt;em&gt;single build&lt;/em&gt;.
The only alternative to that is basically to go down the tree, build some artifacts, then replace transitive dependencies with &lt;em&gt;file&lt;/em&gt; dependencies and cross fingers that everything compiles up to the top.
Of course this is completely unrealistic in the real world, unless you have millions of dollars to spend on rebuilding artifacts (and yes, some organizations do that, that&amp;#8217;s the strategy for debian, for example, which has the &quot;nice&quot; side effect of having applications which have bugs which are not in the initial release, because all applications need to use the &lt;em&gt;same&lt;/em&gt; dependency version).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s why I think the preferred solution, for security, is still to use precompiled binaries (which also would make builds faster in any case), but combine that with &lt;a href=&quot;https://docs.gradle.org/current/userguide/dependency_verification.html&quot;&gt;dependency verification&lt;/a&gt;: it&amp;#8217;s a good tradeoff, which offers the right level of security, while not having to spend incredible amounts of money in rebuilding the entire world (also, it&amp;#8217;s better for the planet).
Note that this also guarantees trust, as your &quot;custom built&quot; binaries will clearly use different signatures, and possibly checksums, than what the users normally expect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While we were talking about building from sources, we &lt;em&gt;also&lt;/em&gt; forgot about one extremely important bit: &lt;em&gt;there is no single dependency graph&lt;/em&gt;, even in a single project.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_building_requires_multiple_dependency_graphs&quot;&gt;Building requires multiple dependency graphs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The most obvious way to illustrate that there&amp;#8217;s no single dependency graph in a project is to thing about &lt;em&gt;tests&lt;/em&gt;.
When you compile your application, there shouldn&amp;#8217;t be any test dependency on the compile classpath.
When you compile your &lt;em&gt;tests&lt;/em&gt;, then you&amp;#8217;d get the dependencies of the application, plus the dependencies of your test framework, plus your additional test dependencies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, you have at least 2 distinct dependency graphs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the application compile classpath (in Gradle, it&amp;#8217;s the &lt;code&gt;compileClasspath&lt;/code&gt; configuration which represents that dependency graph)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the application test compile classpath (in Gradle, it&amp;#8217;s the &lt;code&gt;testCompileClasspath&lt;/code&gt; configuration which represents that dependency graph)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Maven itself makes a difference, with dependency &lt;em&gt;scopes&lt;/em&gt; (&lt;code&gt;compile&lt;/code&gt;, &lt;code&gt;runtime&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &amp;#8230;&amp;#8203;).
You can already see that in practice, we have &lt;em&gt;many more&lt;/em&gt; dependency graphs: compile classpath, runtime classpath, test compile classpath, test runtime classpath, annotation processing path, functional tests compile/runtime classpath, etc.
A project can literally have dozens of different dependency graphs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;More importantly, there can be conflicts in those graphs: for example, when you compile your tests, you may introduce a dependency which will accidentally trigger an &lt;em&gt;upgrade&lt;/em&gt; of a dependency, so you would get a different dependency version during testing and actual run time!
Similarly, your runtime dependencies can introduce transitive dependencies which would have the consequence of having different versions of dependencies at compile time and run time.
Note that Gradle offers different ways to mitigate those real world problems, for example &lt;a href=&quot;https://docs.gradle.org/current/userguide/resolution_strategy_tuning.html#resolution_consistency&quot;&gt;consistent resolution&lt;/a&gt; or &lt;a href=&quot;https://docs.gradle.org/6.2.1/userguide/dependency_version_alignment.html&quot;&gt;version alignment&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I hope that after reading this, it becomes quite clear that &lt;em&gt;there is no single dependency graph&lt;/em&gt;.
Therefore, it&amp;#8217;s a mistake to ask for &quot;what are the dependencies of Micronaut&quot;, because the answer &lt;em&gt;depends on the consumer&lt;/em&gt;.
Not only does it depend on the consumer, but it also depends on either the order of dependencies (Maven for example), or the strategies being used to &quot;force&quot; dependency versions (which are also consumer dependent), or the kind of dependency graph which is resolved (runtime dependencies, compile dependencies).
Of course, we didn&amp;#8217;t mention more advanced features like optional dependencies, for which I like to remind that &lt;a href=&quot;https://blog.gradle.org/optional-dependencies&quot;&gt;they are not optional&lt;/a&gt;, nor did we talk about more advanced, runtime based systems like OSGi which add another layer of complexity to the problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you can take away one thing from this blog post, it&amp;#8217;s to never ask &quot;what are the dependencies of X&quot; anymore: minimally, the question should be more targetted:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;what are the dependencies that X need to compile?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;what are the dependencies that X uses at runtime to run its test suite?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The question &quot;what are the dependencies that X uses at runtime&quot; is only valid for &lt;em&gt;some&lt;/em&gt; applications (for example those which are not subject to platform dependent dependencies), not for &lt;em&gt;libraries&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle quickie: laziness</title>
      <link>https://melix.github.io/blog//2022/05/gradle-laziness.html</link>
      <pubDate>Tue, 24 May 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/05/gradle-laziness.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yesterday, I wrote this tweet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/2022-05-24-tweet.png&quot; alt=&quot;2022 05 24 tweet&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I got a surprisingly high number of answers, so I thought it would be a good idea to expand a bit on the topic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle &lt;a href=&quot;https://docs.gradle.org/current/userguide/lazy_configuration.html&quot;&gt;introduced lazy APIs several years ago&lt;/a&gt;.
Those APIs are mostly directed at plugin authors but some build authors may have to deal with them too.
Lazy APIs are designed to improve performance, by avoiding to create tasks which would never be invoked during a build.
While lots of users wouldn&amp;#8217;t notice the difference between a build using lazy APIs and a build which doesn&amp;#8217;t, in some ecosystems like Android or with large projects, this makes a dramatic difference.
In other words, while Gradle&amp;#8217;s performance is often praised, it&amp;#8217;s easy to break performance by unintentionally trigerring configuration of tasks which shouldn&amp;#8217;t.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_task_configuration&quot;&gt;Task configuration&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The discussion was trigerred when I was doing a code review yesterday.
I saw the following block:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(Test) {
    testLogging {
        showStandardStreams = true
        exceptionFormat = &apos;full&apos;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This block configures logging for all test tasks of the project.
At first glance, this seems appropriate, but there&amp;#8217;s this gotcha: you should use &lt;code&gt;.configureEach&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(Test).configureEach {
    testLogging {
        showStandardStreams = true
        exceptionFormat = &apos;full&apos;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you don&amp;#8217;t, then &lt;em&gt;all tasks of type Test will always be configured&lt;/em&gt;, even if you don&amp;#8217;t call them in a build.
In other words, lazy configuration is about only configuring tasks which are going to be invoked.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Unfortunately, there are no warnings about eager configuration, or &quot;unnecessary&quot; configuration in a build.
If you use &lt;a href=&quot;https://ge.micronaut.io&quot;&gt;Build Scans&lt;/a&gt;, you can have insights about configuration and realize that, but casual users wouldn&amp;#8217;t.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly, this code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;test {
    testLogging {
        showStandardStreams = true
        exceptionFormat = &apos;full&apos;
    }
}
----&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Will configure the &lt;code&gt;test&lt;/code&gt; task (not &lt;em&gt;all&lt;/em&gt; test tasks) eagerly: even if the &lt;code&gt;test&lt;/code&gt; task isn&amp;#8217;t executed in a build, it would be configured.
Now you see the problem: this configuration pattern has been there basically forever, so it&amp;#8217;s hard to remove.
To do lazy configuration, you have to write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.named(&apos;test&apos;) {
    testLogging {
        showStandardStreams = true
        exceptionFormat = &apos;full&apos;
    }
}
----&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Obviously, this isn&amp;#8217;t as nice, DSL-wise.
One thing you may wonder is why Gradle&amp;#8217;s DSL default to the lazy version?
In other words, why doesn&amp;#8217;t it call the lazy version instead of the eager one?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s because of backwards compatiblity: because this pattern has been present since day one in Gradle, eager configuration is everywhere in older builds.
If you search for configuration blocks in Stack Overflow, it&amp;#8217;s very likely that you&amp;#8217;ll end up copy and pasting &lt;em&gt;eager configuration&lt;/em&gt; samples.
But, as the name implies, &lt;em&gt;lazy&lt;/em&gt; configuration has a different behavior than &lt;em&gt;eager&lt;/em&gt;: in the lazy case, the configuration block is invoked &lt;em&gt;only when the task is needed&lt;/em&gt;, either because it&amp;#8217;s going to be executed, or that another task depends on its configuration to configure itself.
In the eager case, configuration is executed immediately: unfortunately there are lots of builds which accidentally depend on this order of execution, so changing from eager to lazy could result in breaking changes!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_what_should_you_use&quot;&gt;What should you use?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The consequence is that there&amp;#8217;s a mix of lazy and eager APIs in Gradle, and making the difference between what is going to trigger configuration or not isn&amp;#8217;t obvious, even for Gradle experts.
Let&amp;#8217;s summarize a few patterns:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you want to configure &lt;em&gt;one particular task&lt;/em&gt; by name, you should write:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.named(&quot;myTask&quot;) {
   // configure the task
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.named(&quot;myTask&quot;, SomeType) {
   // configure the task
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you want to all tasks of a particular type, you should write:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(SomeType).configureEach {
   // configure the task
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you want to create a new task, &lt;em&gt;don&amp;#8217;t use create&lt;/em&gt;, but &lt;em&gt;register&lt;/em&gt; instead:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;myTask&quot;, SomeType) {
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the DSL, the following code that you find in many tutorials would &lt;em&gt;immediately create a task&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;task hello {
   doLast {
       println &quot;Hello!&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So the correct way to do this is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;hello&quot;) {
    doLast {
         println &quot;Hello!&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that the return type of both calls is &lt;em&gt;different&lt;/em&gt;: the eager version will return a &lt;code&gt;Task&lt;/code&gt;, while the 2nd one returns a &lt;code&gt;TaskProvider&lt;/code&gt;.
This is the reason why upgrading plugins isn&amp;#8217;t that trivial, since it&amp;#8217;s a binary breaking change!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_task_collections_and_implicit_dependencies&quot;&gt;Task collections and implicit dependencies&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In &lt;a href=&quot;https://melix.github.io/blog/2022/01/understanding-provider-api.html&quot;&gt;a previous blog post&lt;/a&gt; I explained that the provider API is the right way to handle implicit inputs.
For example, you can pass directly a &lt;code&gt;TaskProvider&lt;/code&gt; as an element of a file collection: Gradle would automatically resolve dependencies and trigger the configuration of that task, include it in the task graph and use its output as an input of the task you&amp;#8217;re invoking.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, understanding lazy APIs means that you should understand &lt;em&gt;when&lt;/em&gt; things are executed.
In the example above, the call &lt;code&gt;tasks.withType(Test)&lt;/code&gt; by itself does &lt;em&gt;not&lt;/em&gt; configure anything.
You can see it as a lazy predicate: it returns a &lt;em&gt;live task collection&lt;/em&gt;, it&amp;#8217;s a declaration of intent: &quot;this models all tasks of type `Test`&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, the following blocks of code are strictly equivalent:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(Test) {
   // configure
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(Test).each {
    // configure
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def testTasks = tasks.withType(Test)
testTasks.each {
    // configure
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In other words, the last version explains the &quot;magic&quot; behind the traditional Gradle DSL.
The first line is lazy, returns a task collection, and it&amp;#8217;s the fact of calling &lt;code&gt;.each&lt;/code&gt; which triggers configuration of all tasks!
Replace &lt;code&gt;.each&lt;/code&gt; with &lt;code&gt;.configureEach&lt;/code&gt; and you are now lazy!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Newer APIs like &lt;code&gt;named&lt;/code&gt; are lazy from day one, but are not necessarily user friendly.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_gradle_puzzle&quot;&gt;A Gradle puzzle&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In effect, &lt;code&gt;named&lt;/code&gt; is lazy in terms of &lt;em&gt;configuration&lt;/em&gt;, but &lt;em&gt;eager&lt;/em&gt; in terms of lookup: it will &lt;strong&gt;fail&lt;/strong&gt; if the task that you&amp;#8217;re looking for doesn&amp;#8217;t exist.
It&amp;#8217;s a bit strange, since in Gradle everything is now supposed to be lazy, so you can&amp;#8217;t know &lt;em&gt;when&lt;/em&gt; a task is going to be available or not.
As an illustration, let&amp;#8217;s explore the following script (don&amp;#8217;t write this in your own builds, this is for demonstration purposes!):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;hello&quot;) {
   doLast {
       println &quot;Hello,&quot;
   }
}

tasks.named(&quot;hello&quot;) {
   doLast {
        println &quot;World!&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you run &lt;code&gt;gradle hello&lt;/code&gt;, then the output is what you expect:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;&amp;gt; Task :hello
Hello,
World!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, &lt;em&gt;invert&lt;/em&gt; the position of the 2 tasks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.named(&quot;hello&quot;) {
   doLast {
        println &quot;World!&quot;
   }
}

tasks.register(&quot;hello&quot;) {
   doLast {
       println &quot;Hello,&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and run again. Boom!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;* Where:
Build file &apos;/tmp/ouudfd/build.gradle&apos; line: 1

* What went wrong:
A problem occurred evaluating root project &apos;ohnoes&apos;.
&amp;gt; Task with name &apos;hello&apos; not found in root project &apos;ohnoes&apos;.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That is very unexpected: I think what most people would expect is, if any change, that the &lt;code&gt;World!&lt;/code&gt; and &lt;code&gt;Hello&lt;/code&gt; outputs would be exchanged.
But because &lt;code&gt;named&lt;/code&gt; &lt;em&gt;eagerly&lt;/em&gt; searches for a task registed with a particular name, it &lt;em&gt;fails&lt;/em&gt; if not found.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, plugin authors who want to react to other plugins, or react to tasks which &lt;em&gt;may&lt;/em&gt; be present or not, tend to use the following API instead:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.matching { it.name == &apos;hello&apos; }.configureEach {
    doLast {
        println &quot;World!&quot;
   }
}

tasks.register(&quot;hello&quot;) {
   doLast {
       println &quot;Hello,&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s run our &lt;code&gt;hello&lt;/code&gt; task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;&amp;gt; Task :hello
World!
Hello,&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yay! No failure anymore, and the output is in the order we expected. Problem solved, right?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, not so fast.
You&amp;#8217;ve used &lt;code&gt;configureEach&lt;/code&gt;, so everything should be lazy, right?
Sorry, nope: the &lt;code&gt;matching&lt;/code&gt; API is an &lt;em&gt;old&lt;/em&gt;, eager API!
Actually, if you look at what the predicate uses, it becomes obvious:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;// T is a Task!
TaskCollection&amp;lt;T&amp;gt; matching(Spec&amp;lt;? super T&amp;gt; var1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because it works on &lt;code&gt;Task&lt;/code&gt; instances, it needs to &lt;em&gt;create and configure the tasks&lt;/em&gt; so that you can run an arbitrary predicate on them!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s why if you have to write things like this, you &lt;strong&gt;must&lt;/strong&gt; guard calls to &lt;code&gt;matching&lt;/code&gt; with a &lt;code&gt;withType&lt;/code&gt; before, which will restrict the set of tasks which will be configured.
For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(Greeter).matching { it.name == &apos;hello&apos; }.configureEach {
   messages.add(&quot;World!&quot;)
}

tasks.register(&quot;hello&quot;, Greeter) {
   messages.add(&quot;Hello,&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course the example is a bit stupid, but it makes sense when you&amp;#8217;re not the one in control of &lt;em&gt;when&lt;/em&gt; a task is configured or even if you don&amp;#8217;t know if it will ever be.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Unfortunately, &lt;a href=&quot;https://github.com/gradle/gradle/issues/16543&quot;&gt;Gradle doesn&amp;#8217;t provide an API which is &lt;em&gt;fully lazy&lt;/em&gt; and lenient to tasks being present or not&lt;/a&gt;.
If you simply want to &lt;em&gt;configure&lt;/em&gt; a task, that is not a big deal since you can simply use &lt;code&gt;configureEach&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.configureEach {
    if (it.name == &apos;hello&apos;) { ... }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is fine because the configuration block will be called for each task being configured.
However, this &lt;code&gt;configureEach&lt;/code&gt; block is a &lt;em&gt;configurer&lt;/em&gt;, not a &lt;em&gt;predicate&lt;/em&gt;, so you can&amp;#8217;t use it as an input to another task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.named(&quot;md5&quot;) {
    inputFiles.from(tasks.named(&quot;userguide&quot;))
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code above would &lt;em&gt;fail&lt;/em&gt; if the &lt;code&gt;userguide&lt;/code&gt; task doesn&amp;#8217;t exist &lt;em&gt;before&lt;/em&gt; the &lt;code&gt;md5&lt;/code&gt; task is configured&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, I have explained why you should use the new lazy APIs instead of their eager counterparts.
I have also described that while they are more verbose, they make it possible to have faster builds by avoiding configuration of tasks which would not be executed.
However, Gradle doesn&amp;#8217;t warn you if you eagerly configure tasks, and it&amp;#8217;s easy to shoot yourself in the foot.
Some would blame the docs, some would blame the APIs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a former Gradler, I would blame none of those: the &lt;a href=&quot;https://docs.gradle.org/current/userguide/lazy_configuration.html&quot;&gt;docs are here&lt;/a&gt;, and changing the APIs to be lazy everywhere is either a binary breaking change (return type of methods which &lt;em&gt;create&lt;/em&gt; instead of &lt;em&gt;register&lt;/em&gt;), or a behavior change (deferred configuration vs immediate configuration).
This makes it particularly complicated to upgrade builds without pissing off a number of users!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Astrophotographie: rendez-vous sur Twitch !</title>
      <link>https://melix.github.io/blog//2022/05/astro-twitch.html</link>
      <pubDate>Tue, 3 May 2022 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2022/05/astro-twitch.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_nous_ne_sommes_pas_que_des_développeurs&quot;&gt;Nous ne sommes pas que des développeurs !&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ma passion, en dehors du développement, c&amp;#8217;est l&amp;#8217;astronomie.
Depuis quelques années, je me suis lancé dans l&amp;#8217;astrophotographie: je ne fais quasiment plus que ça.
Pour un développeur comme moi, c&amp;#8217;est assez intéressant de constater que lorsque je poste sur Twitter une photo que j&amp;#8217;ai faite, j&amp;#8217;ai bien souvent plus de réponses et de likes que sur mes tweets professionnels (ce qui est parfois vexant, lol !).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_des_lives_sur_twitch&quot;&gt;Des lives sur Twitch&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div style=&quot;font-size: 1.5em; padding: 6px; background-color: lightblue; border: solid; margin: 2em; text-align: center&quot;&gt;
&lt;b&gt;Edit&lt;/b&gt;: C&apos;est fait ! L&apos;expérience fut enrichissante pour moi, retrouvez le replay sur &lt;a href=&quot;https://www.youtube.com/watch?v=Hudtta97gDU&quot;&gt;Youtube&lt;/a&gt;&lt;/b&gt;.
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai, au final, souvent les mêmes questions qui reviennent:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Qu&amp;#8217;est ce que c&amp;#8217;est ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Quel matériel tu utilises ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Combien de fois ça grossit ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Est-ce que ce sont de vraies couleurs ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Combien de temps de pose ?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;et bien d&amp;#8217;autres !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, l&amp;#8217;an dernier, je me suis lancé ce défi de faire un talk dans une conférence de développeurs (Devoxx) sur le sujet des &quot;miracles du logiciel&quot; en termes d&amp;#8217;astrophotographie.
Malheureusement, le talk n&amp;#8217;a pas été retenu, mais j&amp;#8217;ai conservé en tête l&amp;#8217;idée de présenter quelque chose.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, envie de savoir comment on fait des photos comme celle-ci ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;a class=&quot;image&quot; href=&quot;https://www.astrobin.com/full/ollbl5/0/&quot;&gt;&lt;img src=&quot;/blog/img/astro/2021-11-09-flaming-star-nebula.jpg&quot; alt=&quot;2021 11 09 flaming star nebula&quot;&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;title&quot;&gt;Figure 1. The flaming star nebula&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Aujourd&amp;#8217;hui, je vous annonce donc un premier live sur Twitch pour parler d&amp;#8217;astrophotographie !
Je dis premier, parce que je pense qu&amp;#8217;il y a de quoi en faire plusieurs avant d&amp;#8217;avoir fait le tour du sujet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Attention, ça sera sans prétention, pas aussi préparé qu&amp;#8217;un talk en conférence.
Ca sera aussi mon tout premier live et donc probablement plein de problèmes techniques, mais il faut bien se lancer un jour !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;annonce donc le &lt;strong&gt;jeudi 12 mai à 20h&lt;/strong&gt; sur &lt;a href=&quot;https://www.twitch.tv/melix_fr&quot;&gt;ma chaîne Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le premier sujet sera autour de mon setup photographique: quel matériel j&amp;#8217;utilise, les principes de base de l&amp;#8217;acquisition photo.
Attention, il ne s&amp;#8217;agira pas d&amp;#8217;une présentation générique sur l&amp;#8217;astrophoto, mais bien d&amp;#8217;une présentation spécifique à mon matériel, soupoudrée de détails sur comment ça fonctionne en règle générale.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En fonction du succès et/ou de ce que j&amp;#8217;arrive à couvrir, d&amp;#8217;autres lives seront programmés.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A bientôt !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Conditional dependencies with Gradle</title>
      <link>https://melix.github.io/blog//2022/03/gradle-conditional-dependencies.html</link>
      <pubDate>Mon, 21 Mar 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/03/gradle-conditional-dependencies.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you ever wrote a Gradle plugin for a framework (e.g &lt;a href=&quot;https://micronaut.io&quot;&gt;Micronaut&lt;/a&gt;) or a plugin which needs to add dependencies if the user configures a particular flag, then it is likely that you&amp;#8217;ve faced some ordering issues.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, imagine that you have this DSL:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;micronaut {
    useNetty = true
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Obviously, &lt;em&gt;at some point in time&lt;/em&gt;, you have to figure out if the property &lt;code&gt;useNetty&lt;/code&gt; is set in order to transparently add dependencies.
A naive solution is to use the good old &lt;code&gt;afterEvaluate&lt;/code&gt; block.
Many plugins do this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;afterEvaluate {
    dependencies {
        if (micronaut.useNetty.get()) {
            implementation(&quot;io.netty:netty-buffer:4.1.75.Final&quot;)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem is that while &lt;em&gt;afterEvaluate&lt;/em&gt; seems to fix the problem, it&amp;#8217;s just a dirty workaround which defers the problem to a later stage: depending on the plugins which are applied, which themselves could use &lt;code&gt;afterEvaluate&lt;/code&gt;, your block may, or may not, see the &quot;final&quot; configuration state.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a &lt;a href=&quot;https://melix.github.io/blog/2022/01/understanding-provider-api.html&quot;&gt;previous post&lt;/a&gt;, I introduced Gradle&amp;#8217;s provider API.
In this post, we&amp;#8217;re going to show how to use it to properly fix this problem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_using_providers_for_dependencies&quot;&gt;Using providers for dependencies&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s start with the easiest.
It&amp;#8217;s a common requirement of a plugin to provide the ability to override the version of a runtime.
For example, the &lt;code&gt;checkstyle&lt;/code&gt; plugin would, by default, use version of checkstyle by convention, but it would still let you override the version if you want to use a different one.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Micronaut provides a similar feature:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;micronaut {
    version = &quot;3.3.1&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The Micronaut dependencies to be added on the user classpath depend on the value of the &lt;code&gt;version&lt;/code&gt; in our &lt;code&gt;micronaut&lt;/code&gt; extension.
Let&amp;#8217;s see how we can implement this.
Let&amp;#8217;s create our Gradle project (we&amp;#8217;re assuming that you have Gradle 7.4 installed):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ mkdir conditional-deps &amp;amp;&amp;amp; cd conditional-deps
$ gradle init --dsl groovy \
   --type java-library \
   --package me.champeau.demo \
   --incubating \
   --test-framework junit-jupiter&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now we&amp;#8217;re going to create a folder for our build logic, which will contain our plugin sources:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ mkdir -p build-logic/src/main/groovy/my/plugin&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s update the &lt;code&gt;settings.gradle&lt;/code&gt; file to &lt;em&gt;include&lt;/em&gt; that build logic:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;pluginManagement {
    // include our plugin
    includeBuild &quot;build-logic&quot;
}
rootProject.name = &apos;provider-dependencies&apos;
include(&apos;lib&apos;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For now our plugin is an empty shell, so let&amp;#8217;s create its &lt;code&gt;build.gradle&lt;/code&gt; file so that we can use a &lt;a href=&quot;https://docs.gradle.org/7.4.1/userguide/custom_plugins.html#sec:precompiled_plugins&quot;&gt;precompiled script plugin&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &apos;groovy-gradle-plugin&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s define our extension, which is simply about declaring an &lt;em&gt;interface&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/src/main/groovy/my/plugin/MicronautExtension.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;package my.plugin

import org.gradle.api.provider.Property

interface MicronautExtension {
    Property&amp;lt;String&amp;gt; getVersion()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s now time to create our plugin: precompiled script plugins are a very easy way to create a plugin, simply by declaring a file in &lt;code&gt;build-logic/src/main/groovy&lt;/code&gt; which name ends with &lt;code&gt;.gradle&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/src/main/groovy/my.plugin.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import my.plugin.MicronautExtension

def micronautExtension = extensions.create(&quot;micronaut&quot;, MicronautExtension) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
micronautExtension.version.convention(&quot;3.3.0&quot;)                              &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create our extension, named &quot;micronaut&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Assign a default value to the &quot;version&quot; property&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By convention, our plugin id will be &lt;code&gt;my.plugin&lt;/code&gt; (it&amp;#8217;s derived from the file name).
Our plugin is responsible for creating the extension, and it assigns a &lt;em&gt;convention&lt;/em&gt; value to the &lt;code&gt;version&lt;/code&gt; property: this is the value which is going to be used if the user doesn&amp;#8217;t declare anything explicitly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then we can &lt;em&gt;use&lt;/em&gt; the plugin in our main build, that is, in the &lt;code&gt;lib&lt;/code&gt; project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;lib/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    // Apply the java-library plugin for API and implementation separation.
    id &apos;java-library&apos;
    // And now apply our plugin
    id &apos;my-plugin&apos;
}

micronaut {
   // empty for now
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If we look at the &lt;code&gt;lib&lt;/code&gt; compile classpath, it will not include any Micronaut dependency for now:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew lib:dependencies --configuration compileClasspath

------------------------------------------------------------
Project &apos;:lib&apos;
------------------------------------------------------------

compileClasspath - Compile classpath for source set &apos;main&apos;.
+--- org.apache.commons:commons-math3:3.6.1
\--- com.google.guava:guava:30.1.1-jre
     +--- com.google.guava:failureaccess:1.0.1
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.8.0
     +--- com.google.errorprone:error_prone_annotations:2.5.1
     \--- com.google.j2objc:j2objc-annotations:1.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Our goal is to add a dependency which is &lt;em&gt;derived from&lt;/em&gt; the version defined in our Micronaut extension, so let&amp;#8217;s do this.
Edit our &lt;code&gt;build-logic&lt;/code&gt; plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/src/main/groovy/my.plugin.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import my.plugin.MicronautExtension

def micronautExtension = extensions.create(&quot;micronaut&quot;, MicronautExtension)
micronautExtension.version.convention(&quot;3.3.0&quot;)

dependencies {
    implementation micronautExtension.version.map {
        v -&amp;gt; &quot;io.micronaut:micronaut-core:$v&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s run our dependencies report again:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew lib:dependencies --configuration compileClasspath

&amp;gt; Task :lib:dependencies

------------------------------------------------------------
Project &apos;:lib&apos;
------------------------------------------------------------

compileClasspath - Compile classpath for source set &apos;main&apos;.
+--- org.apache.commons:commons-math3:3.6.1
+--- io.micronaut:micronaut-core:3.3.0
|    \--- org.slf4j:slf4j-api:1.7.29
\--- com.google.guava:guava:30.1.1-jre
     +--- com.google.guava:failureaccess:1.0.1
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.8.0
     +--- com.google.errorprone:error_prone_annotations:2.5.1
     \--- com.google.j2objc:j2objc-annotations:1.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Victory! Now we can see our &lt;code&gt;micronaut-core&lt;/code&gt; dependency.
How did we do this?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that instead of using &lt;code&gt;afterEvaluate&lt;/code&gt;, what we did is &lt;em&gt;adding a dependency&lt;/em&gt;, but instead of using the traditional dependency notation, we used a &lt;em&gt;provider&lt;/em&gt;: the actual dependency string is computed &lt;em&gt;only when we need it&lt;/em&gt;.
We can check that we can actually configure the version via our extension by editing our build file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;lib/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;micronaut {
   version = &quot;3.3.1&quot; // override the convention
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew lib:dependencies --configuration compileClasspath

&amp;gt; Task :lib:dependencies

------------------------------------------------------------
Project &apos;:lib&apos;
------------------------------------------------------------

compileClasspath - Compile classpath for source set &apos;main&apos;.
+--- org.apache.commons:commons-math3:3.6.1
+--- io.micronaut:micronaut-core:3.3.1
|    \--- org.slf4j:slf4j-api:1.7.29
\--- com.google.guava:guava:30.1.1-jre
     +--- com.google.guava:failureaccess:1.0.1
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.8.0
     +--- com.google.errorprone:error_prone_annotations:2.5.1
     \--- com.google.j2objc:j2objc-annotations:1.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_maybe_add_maybe_not&quot;&gt;Maybe add, maybe not!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the previous example, we have &lt;em&gt;systematically added&lt;/em&gt; a dependency, based on the version defined in the extension.
What if we want to add a dependency if a property is set to a particular value?
For this purpose, let&amp;#8217;s say that we define a &lt;code&gt;runtime&lt;/code&gt; property which will tell what runtime to use.
Let&amp;#8217;s add this property to our extension:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/src/main/groovy/my/plugin/MicronautExtension.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;package my.plugin

import org.gradle.api.provider.Property

interface MicronautExtension {
    Property&amp;lt;String&amp;gt; getVersion()
    Property&amp;lt;String&amp;gt; getRuntime()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s update our plugin to use that property, and add a dependency based on the value of the &lt;em&gt;runtime&lt;/em&gt; property:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build-logic/src/main/groovy/my.plugin.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import my.plugin.MicronautExtension

def micronautExtension = extensions.create(&quot;micronaut&quot;, MicronautExtension)
micronautExtension.version.convention(&quot;3.3.0&quot;)

dependencies {
    implementation micronautExtension.version.map { v -&amp;gt;
        &quot;io.micronaut:micronaut-core:$v&quot;
    }

    implementation micronautExtension.runtime.map { r -&amp;gt;
        switch(r) {
            case &apos;netty&apos;:                                                   &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
                return &quot;io.netty:netty-buffer:4.1.75.Final&quot;
            case &apos;tomcat&apos;:
                return &quot;org.apache.tomcat.embed:tomcat-embed-core:10.0.18&quot;  &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;
            default:
                return null                                                 &lt;b class=&quot;conum&quot;&gt;(3)&lt;/b&gt;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add a dependency if the runtime is set to netty&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a dependency if the runtime is set to tomcat&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But do nothing if the runtime isn&amp;#8217;t set&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The trick, therefore, is to &lt;em&gt;return null&lt;/em&gt; in the provider in case no dependency needs to be added.
So let&amp;#8217;s check first that without declaring anything, we don&amp;#8217;t have any dependency added:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew lib:dependencies --configuration compileClasspath

&amp;gt; Task :lib:dependencies

------------------------------------------------------------
Project &apos;:lib&apos;
------------------------------------------------------------

compileClasspath - Compile classpath for source set &apos;main&apos;.
+--- org.apache.commons:commons-math3:3.6.1
+--- io.micronaut:micronaut-core:3.3.1
|    \--- org.slf4j:slf4j-api:1.7.29
\--- com.google.guava:guava:30.1.1-jre
     +--- com.google.guava:failureaccess:1.0.1
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.8.0
     +--- com.google.errorprone:error_prone_annotations:2.5.1
     \--- com.google.j2objc:j2objc-annotations:1.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s switch to use &lt;code&gt;tomcat&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;lib/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;micronaut {
   version = &quot;3.3.1&quot;
   runtime = &quot;tomcat&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew lib:dependencies --configuration compileClasspath

&amp;gt; Task :lib:dependencies

------------------------------------------------------------
Project &apos;:lib&apos;
------------------------------------------------------------

compileClasspath - Compile classpath for source set &apos;main&apos;.
+--- org.apache.commons:commons-math3:3.6.1
+--- io.micronaut:micronaut-core:3.3.1
|    \--- org.slf4j:slf4j-api:1.7.29
+--- org.apache.tomcat.embed:tomcat-embed-core:10.0.18
|    \--- org.apache.tomcat:tomcat-annotations-api:10.0.18
\--- com.google.guava:guava:30.1.1-jre
     +--- com.google.guava:failureaccess:1.0.1
     +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
     +--- com.google.code.findbugs:jsr305:3.0.2
     +--- org.checkerframework:checker-qual:3.8.0
     +--- com.google.errorprone:error_prone_annotations:2.5.1
     \--- com.google.j2objc:j2objc-annotations:1.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note how the dependency on Tomcat is added!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_more_complex_use_cases_are_supported&quot;&gt;More complex use cases are supported!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We&amp;#8217;ve shown how to add a dependency and derive the dependency notation from the version defined in our extension.
We&amp;#8217;ve then seen how we could add a dependency, or not, based on the value of an extension: either return a &lt;em&gt;supported dependency notation&lt;/em&gt;, or &lt;em&gt;null&lt;/em&gt; if nothing needs to be added.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle actually supports more complex cases, that I will let as an exercise to the reader.
For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;adding a dependency provider and configure its rich version (see &lt;a href=&quot;https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/dsl/DependencyHandler.html#addProvider-java.lang.String-org.gradle.api.provider.Provider-org.gradle.api.Action-&quot;&gt;DependencyHandler#addProvider&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;adding a &lt;em&gt;list&lt;/em&gt; of dependencies, instead of a &lt;em&gt;single&lt;/em&gt; dependence (see &lt;a href=&quot;https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/Configuration.html#getDependencies--&quot;&gt;Configuration#getDependencies&lt;/a&gt; and &lt;a href=&quot;https://docs.gradle.org/current/javadoc/org/gradle/api/DomainObjectCollection.html#addAllLater-org.gradle.api.provider.Provider-&quot;&gt;DependencySet#addAllLater&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;computing a dependency from two or more providers (see &lt;a href=&quot;https://docs.gradle.org/current/javadoc/org/gradle/api/provider/Provider.html#zip-org.gradle.api.provider.Provider-java.util.function.BiFunction-&quot;&gt;Provider#zip&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, we&amp;#8217;ve seen how to leverage Gradle&amp;#8217;s provider API to properly implement plugins which need to add dependencies conditionally.
This can either mean that they need to add dependencies which version depend on some user configuration, or even full dependency notations which depend on configuration.
The interest of using the provider API again lies in the fact that it is &lt;em&gt;lazy&lt;/em&gt; and therefore is (largely) immune to ordering issues: instead of relying on hooks like &lt;code&gt;afterEvaluate&lt;/code&gt; which come with a number of drawbacks (reliability, ordering, interaction with other plugins), we rely on the fact that it&amp;#8217;s only when a value is &lt;em&gt;needed&lt;/em&gt; that it is computed.
At this moment, we know that the configuration is complete, so we can guarantee that our dependencies will be correct.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Using the Micronaut Version Catalog</title>
      <link>https://melix.github.io/blog//2022/02/micronaut-version-catalog.html</link>
      <pubDate>Tue, 8 Feb 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/02/micronaut-version-catalog.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the &lt;a href=&quot;https://docs.gradle.org/7.4/release-notes.html&quot;&gt;release of Gradle 7.4&lt;/a&gt;, Micronaut users now have an interesting option to manage their dependencies: using Gradle&amp;#8217;s &lt;a href=&quot;https://docs.gradle.org/current/userguide/platforms.html#sub:central-declaration-of-dependencies&quot;&gt;version catalogs&lt;/a&gt;.
Indeed, for a few releases already, Micronaut has shipped its own version catalog alongside its BOM.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s explore how to use it and what&amp;#8217;s the benefit.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_what_is_a_version_catalog&quot;&gt;What is a version catalog?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, a version catalog allows centralizing dependency versions in a single place.
Instead a build script, a typical dependency declaration looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation(&quot;org.apache.slf4j:slf4j-api:1.7.25&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With a version catalog, the declaration looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    implementation(libs.slf4j)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And the dependency coordinates are defined in the &lt;code&gt;gradle/libs.versions.toml&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
slf4j = &quot;1.7.25&quot;

[libraries]
slf4j = { module = &quot;org.apache.slf4j&quot;, version.ref = &quot;slf4j&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are a couple of advantages in doing so:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;dependency versions are centralized in this TOML file&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the catalogs create &quot;type safe accessors&quot; which are completed by the IDE (although to my knowledge completion is only supported by IntelliJ IDEA with the Kotlin DSL)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can read a more complete description about version catalogs in &lt;a href=&quot;https://melix.github.io/blog/2021/03/version-catalogs.html&quot;&gt;this blog post I wrote a few months ago&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_micronaut_version_catalog&quot;&gt;The Micronaut version catalog&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, frameworks like Micronaut can &lt;em&gt;publish&lt;/em&gt; version catalogs, which are then usable in your projects.
You can then think of the Micronaut version catalog as a list of dependencies to pick up from: you don&amp;#8217;t have to think about a version to choose, you can simply use the &quot;recommendation&quot; from Micronaut, but you don&amp;#8217;t have to remember the dependency coordinates either.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_importing_the_micronaut_version_catalog&quot;&gt;Importing the Micronaut version catalog&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s start with a project that you can generate using the Micronaut CLI:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;mn create-app catalog&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;(alternatively, download the project using &lt;a href=&quot;https://launch.micronaut.io/&quot;&gt;Micronaut Launch&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Open the generated project and update the Gradle version by changing the &lt;code&gt;gradle/gradle-wrapper.properties&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, in order to import the Micronaut version catalog, add this to your &lt;code&gt;settings.gradle&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencyResolutionManagement {
    repositories {
        mavenCentral()
    }
    versionCatalogs {
        create(&quot;mn&quot;) {
            from(&quot;io.micronaut:micronaut-bom:${micronautVersion}&quot;)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, we&amp;#8217;re creating a new version catalog called &lt;code&gt;mn&lt;/code&gt;.
Internally, Gradle will automatically download the catalog which is &lt;a href=&quot;https://repo1.maven.org/maven2/io/micronaut/micronaut-bom/3.3.1/&quot;&gt;published at the same GAV coordinates as its BOM&lt;/a&gt; as a &lt;a href=&quot;https://repo1.maven.org/maven2/io/micronaut/micronaut-bom/3.3.1/&quot;&gt;TOML file&lt;/a&gt; and expose it to your build scripts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s open our &lt;code&gt;build.gradle&lt;/code&gt; file.
By default it defines the following dependencies:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    annotationProcessor(&quot;io.micronaut:micronaut-http-validation&quot;)
    implementation(&quot;io.micronaut:micronaut-http-client&quot;)
    implementation(&quot;io.micronaut:micronaut-jackson-databind&quot;)
    implementation(&quot;io.micronaut:micronaut-runtime&quot;)
    implementation(&quot;jakarta.annotation:jakarta.annotation-api&quot;)
    runtimeOnly(&quot;ch.qos.logback:logback-classic&quot;)
    implementation(&quot;io.micronaut:micronaut-validation&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, we can replace this with the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;dependencies {
    annotationProcessor(mn.micronaut.http.validation)
    implementation(mn.micronaut.http.client)
    implementation(mn.micronaut.jackson.databind)
    implementation(mn.micronaut.runtime)
    implementation(mn.jakarta.annotation.api)
    runtimeOnly(mn.logback)
    implementation(mn.micronaut.validation)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What happened here?
Basically, we replaced hardcoded dependency coordinates with references to the &lt;code&gt;mn&lt;/code&gt; version catalog.
It&amp;#8217;s particularly interesting if you are using the Kotlin DSL as I mentioned earlier, because in this case, the dependency notations are &lt;em&gt;type-safe&lt;/em&gt;: you &lt;em&gt;can&amp;#8217;t&lt;/em&gt; make a typo in dependency coordinates, and you get completion:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/catalog/catalog-completion.gif&quot; alt=&quot;catalog completion&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nice!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_future_work&quot;&gt;Future work&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Version catalogs will probably be enabled by default in future releases of Micronaut, which means that projects created via &lt;a href=&quot;https://launch.micronaut.io/&quot;&gt;Micronaut Launch&lt;/a&gt; or the CLI tool would automatically use the catalog, so you don&amp;#8217;t have to do the conversion described in this blog post. Stay tuned!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Understanding Gradle plugins: the provider API</title>
      <link>https://melix.github.io/blog//2022/01/understanding-provider-api.html</link>
      <pubDate>Mon, 24 Jan 2022 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2022/01/understanding-provider-api.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last week, a colleague of mine pinged me about a problem he was facing in a new Micronaut module, with &lt;a href=&quot;https://github.com/JetBrains/gradle-grammar-kit-plugin&quot;&gt;Jetbrains&apos; Grammar-Kit plugin&lt;/a&gt;, a plugin which integrates with &lt;a href=&quot;https://jflex.de/manual.html&quot;&gt;JFlex&lt;/a&gt;.
We discovered a couple of issues:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the plugin is adding repositories transparently to the build, in particular Jitpack.io and an internal Jetbrains mirror, which is a very bad practice as it is introducing a security risk, and could also lead to build reproducibility problems&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the plugin isn&amp;#8217;t compatible with Gradle&amp;#8217;s lazy configuration API, making the build slower than it could be, by forcing the creation of tasks which do not necessarily need to be called&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, we also discovered that the JFlex API itself has problems: it&amp;#8217;s using shared mutable state (here &lt;em&gt;static state&lt;/em&gt;) for configuration, making it inherently not thread safe.
Because what we had to do was pretty simple (take a jflex file and generate a lexer from it), we took advantage of this to write our own Gradle plugin to handle calls to JFlex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, the question I got from my colleague was legitimate:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;How do I link the task to run in the right phase, create a proper output dir, and add it to the java compile source set? Is there a good example plugin that does source generation that I could look at?&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post we&amp;#8217;re going to answer those questions and show how Gradle elegantly solves all the above problems.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_anatomy_of_a_plugin&quot;&gt;Anatomy of a plugin&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Gradle, a plugin essentially consists in registering a number of tasks (things which execute actions, like compiling sources), or so-called extensions (exposed to the user in the form of a DSL for configuring the build).
There isn&amp;#8217;t a difference between what a plugin can do and what you can do in a build script, however, as soon as you have things which go beyond &lt;em&gt;configuration&lt;/em&gt;, it&amp;#8217;s a good idea to move things into a plugin.
The nice thing is that creating a plugin in Gradle is quite straightforward, and doesn&amp;#8217;t even require you to publish the plugin on Maven Central or the Gradle Plugin Repository: everything can be local to your project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In our case, we want to create a task which is going to invoke the JFlex library to parse some &lt;code&gt;.jflex&lt;/code&gt; files and generate &lt;code&gt;.java&lt;/code&gt; files, so let&amp;#8217;s do it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, we&amp;#8217;re going to create a directory for our plugin, a &lt;code&gt;jflex-plugin&lt;/code&gt; directory at the root of our existing project.
We&amp;#8217;re also going to create 2 files in that directory:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;flex-plugin/settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;rootProject.name = &apos;jflex-plugin&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;flex-plugin/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &apos;java-gradle-plugin&apos;
}

repositories {
    mavenCentral()
}

dependencies {
    implementation &apos;de.jflex:jflex:1.8.2&apos;
}

gradlePlugin {
    plugins {
        jflex {
            id = &apos;io.micronaut.internal.jflex&apos;
            implementationClass = &apos;io.micronaut.internal.jflex.JFlexPlugin&apos;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What does this already tell us?
First of all, that our plugin is an independent Gradle project: it lives in the same repository as our main project, but it&amp;#8217;s really an independent build.
Second, it defines a &lt;code&gt;java-gradle-plugin&lt;/code&gt;, which is the Gradle way of saying &quot;this is a plugin for Gradle, written in Java&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This plugin has an implementation dependency on &lt;code&gt;jflex&lt;/code&gt;, and it declares the &lt;code&gt;id&lt;/code&gt; of the plugin, as well as its implementation class.
This is all the boilerplate you have to write to create a plugin, really.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because our main build is going to use this plugin, we also have to edit the main build &lt;code&gt;settings.gradle&lt;/code&gt; file to &lt;em&gt;include&lt;/em&gt; that plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;includeBuild &quot;jflex-plugin&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This makes it possible to apply our JFlex plugin in our project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &apos;java-library&apos;
    id &apos;io.micronaut.internal.jflex&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We use the plugin id that we have defined in our plugin descriptor.
This is how Gradle knows how to wire things together: by using this plugin request, it will automatically trigger the &lt;code&gt;jflex-plugin&lt;/code&gt; build.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
It wouldn&amp;#8217;t bother building the plugin if it wasn&amp;#8217;t used at all, which would be the case, for example, if we had multiple subprojects and that only one of them uses the plugin: depending on what we build, we may need to build the plugin or not.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_provider_api&quot;&gt;The provider API&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the sake of learning, we&amp;#8217;ll start our implementation with what is most &quot;natural&quot; to developers: if you are familiar with Maven, you&amp;#8217;ll think of a Mojo.
If you are familiar with Ant, it&amp;#8217;s a task.
Similarly, in Gradle, the unit which is responsible for executing an action is called a task.
In our case, we want a task which is going to read JFlex files and generate sources.
Here&amp;#8217;s its skeleton:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;jflex-plugin/src/main/java/io/micronaut/internal/jflex/JFlexTask.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@CacheableTask                                                  // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
public abstract class JFlexTask extends DefaultTask {           // &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;

    @InputDirectory                                             // &lt;b class=&quot;conum&quot;&gt;(3)&lt;/b&gt;
    @PathSensitive(PathSensitivity.RELATIVE)
    public abstract DirectoryProperty getSourceDirectory();

    @OutputDirectory                                            // &lt;b class=&quot;conum&quot;&gt;(4)&lt;/b&gt;
    public abstract DirectoryProperty getOutputDirectory();

    @TaskAction                                                 // &lt;b class=&quot;conum&quot;&gt;(5)&lt;/b&gt;
    public void generateSources() {
      // call JFlex library
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;This annotation tells Gradle that the result of executing this task can be cached&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;every Gradle task needs to extend the &lt;code&gt;DefaultTask&lt;/code&gt; type&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;em&gt;input&lt;/em&gt; of our task is a directory containing JFlex files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;em&gt;output&lt;/em&gt; of our task is going to be a directory containing generated Java files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;this is the main task action, which is going to call JFlex&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s explore a bit how this task is defined.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, note how our task is defined &lt;em&gt;abstract&lt;/em&gt;: this is because we will let Gradle generate boilerplate code for us, in particular how to &lt;em&gt;inject&lt;/em&gt; the input and output properties.
We&amp;#8217;ll see later more reasons why it&amp;#8217;s interesting to let Gradle to this for you, but for now the obvious reason is that it reduces the amount of code you have to write: you don&amp;#8217;t need to know how to create a &lt;code&gt;DirectoryProperty&lt;/code&gt;: Gradle will do it for you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Second, note how we are using &lt;code&gt;DirectoryProperty&lt;/code&gt; as the type for our input and output properties.
This is a very important Gradle type, which belongs to the so-called &quot;provider API&quot; or, as you can sometimes read, the &quot;lazy API&quot;.
Most of the ordering problems that earlier versions of Gradle had are fixed by this API, so use it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One thing we can notice is that it&amp;#8217;s &lt;em&gt;strongly typed&lt;/em&gt;: to declare an input directory, we don&amp;#8217;t define the property as a &lt;em&gt;File&lt;/em&gt; or &lt;em&gt;Path&lt;/em&gt;: it&amp;#8217;s a &lt;em&gt;directory&lt;/em&gt;, which helps both Gradle and users understand what you are supposed to give as an input: if the property is set to a regular file, then Gradle can provide a reasonable error message explaining that it expected a directory instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s time to introduce how you could use this type in a build script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;generateLexer&quot;, JFlexTask) {
    sourceDirectory.set(layout.projectDirectory.dir(&apos;src/main/jflex&apos;)) // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
    outputDirectory.set(layout.buildDirectory.dir(&apos;generated/jflex&apos;))  // &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;set the input directory to &lt;code&gt;src/main/jflex&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;set the output directory to &lt;code&gt;build/generated/jflex&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It may sound a bit complicated to declare, especially if you were used to the following syntax:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;generateLexer&quot;, JFlexTask) {
    sourceDirectory = file(&quot;src/main/jflex&quot;)
    outputDirectory = file(&quot;build/generated/jflex&apos;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;code&gt;register&lt;/code&gt; is the new &lt;code&gt;create&lt;/code&gt;: you should never use &lt;em&gt;create&lt;/em&gt; anymore, as it eagerly creates tasks, which means configuring them &lt;em&gt;even if they won&amp;#8217;t participate in the task graph&lt;/em&gt;, while &lt;em&gt;register&lt;/em&gt; is lazy: if a task needs to be executed, and only if, it&amp;#8217;s going to be configured.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Interestingly, this syntax &lt;code&gt;outputDirectory = file(&quot;build/generated/jflex&apos;)&lt;/code&gt; is still valid with our properties and would lead to the same result if executed.
It&amp;#8217;s simpler, so why should you bother with the more complex syntax?
To understand this, let&amp;#8217;s focus on the output directory, which makes it more obvious what is going on: compare &lt;code&gt;build/generated/jflex&lt;/code&gt; with &lt;code&gt;layout.buildDirectory.dir(&apos;generated/jflex&apos;)&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the 1st case, the output directory is &lt;em&gt;hardcoded&lt;/em&gt; to the &lt;code&gt;build/generated/jflex&lt;/code&gt; directory.
In the 2nd case, the output directory is &lt;em&gt;derived from&lt;/em&gt; the location of the build directory.
It means that if, for some reason, your build is configured to use a different output directory than the conventional &lt;code&gt;build&lt;/code&gt; directory, say &lt;code&gt;target&lt;/code&gt; (as in Maven).
In the 1st case, the output directory of the task would be &lt;code&gt;build/generated/jflex&lt;/code&gt;, so it would be writing to the wrong directory.
In the 2nd case, the output would be correctly wired to &lt;code&gt;target/generated/jflex&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some smart Gradle users might think they could workaround the problem by using &lt;code&gt;file(&quot;$buildDir/generated/jflex&quot;)&lt;/code&gt; instead.
That&amp;#8217;s better, but not sufficient, because the result depends on &lt;em&gt;when&lt;/em&gt; this is called: if the build directory is changed &lt;em&gt;after&lt;/em&gt; the task is configured, then you&amp;#8217;d get the wrong result, which is why lots of users start to randomly add &lt;code&gt;afterEvaluate&lt;/code&gt; to workaround such problems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Outcome #1&lt;/strong&gt;: The provider API solves ordering issues and avoids spurious calls to &lt;code&gt;afterEvaluate&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_convention_plugins&quot;&gt;Convention plugins&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the beginning of this blog post, I mentioned that what we want to avoid users to create tasks directly in their build scripts: this is a sign that the code should be moved to a &lt;em&gt;plugin&lt;/em&gt;.
This is exactly what we&amp;#8217;re going to do, so instead of asking the user to declare the task, we&amp;#8217;re going to do it for them.
It&amp;#8217;s time to create our plugin class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;jflex-plugin/src/main/java/io/micronaut/internal/jflex/JFlexPlugin.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class JFlexPlugin implements Plugin&amp;lt;Project&amp;gt; {                                  // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
    @Override
    public void apply(Project project) {
        project.getPluginManager().apply(JavaPlugin.class);                            // &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;
        JavaPluginExtension javaExt = project.getExtensions()
           .getByType(JavaPluginExtension.class);                                      // &lt;b class=&quot;conum&quot;&gt;(3)&lt;/b&gt;
        TaskProvider&amp;lt;JFlexTask&amp;gt; generateLexer = project.getTasks()
            .register(&quot;generateLexer&quot;, JFlexTask.class, task -&amp;gt; {                      // &lt;b class=&quot;conum&quot;&gt;(4)&lt;/b&gt;
               task.setGroup(LifecycleBasePlugin.BUILD_GROUP);
               task.setDescription(&quot;Generates lexer files from JFlex grammar files.&quot;);
               task.getSourceDirectory().convention(
                    project.getLayout().getProjectDirectory().dir(&quot;src/main/jflex&quot;)    // &lt;b class=&quot;conum&quot;&gt;(5)&lt;/b&gt;
               );
               task.getOutputDirectory().convention(
                    project.getLayout().getBuildDirectory().dir(&quot;generated/jflex&quot;)     // &lt;b class=&quot;conum&quot;&gt;(6)&lt;/b&gt;
               );
        });
        // Register the output of the JFlex task as generated sources
        javaExt.getSourceSets()
                .getByName(SourceSet.MAIN_SOURCE_SET_NAME)
                .getJava()
                .srcDir(generateLexer);                                                // &lt;b class=&quot;conum&quot;&gt;(7)&lt;/b&gt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Declare a &lt;em&gt;project scoped&lt;/em&gt; plugin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This plugin will contribute Java sources, so it &lt;em&gt;depends on&lt;/em&gt; the Java plugin, let&amp;#8217;s apply it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Java plugin defines a Java extension that we&amp;#8217;re going to need&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Registers our &lt;code&gt;generateLexer&lt;/code&gt; task&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Defines the conventional (&lt;em&gt;default&lt;/em&gt;) location of JFlex source files&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Defines the conventional (&lt;em&gt;default&lt;/em&gt;) location of generated sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Defines that the output of the task are Java files which need to be compiled&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I recommend writing plugins in plain Java, but you could use Groovy or Kotlin.
It makes things a bit more verbose, but they are clearer and &quot;DSL magic&quot; free.
Let&amp;#8217;s explore what the plugin is doing.
First of all, it&amp;#8217;s a &lt;em&gt;project plugin&lt;/em&gt;, which basically means it&amp;#8217;s a plugin which is supposed to be applied on a &lt;em&gt;project&lt;/em&gt; build file, so typically a &lt;code&gt;build.gradle&lt;/code&gt; file.
There are other kinds of plugins in Gradle, which I won&amp;#8217;t cover in this post.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the most part, the plugin does &lt;em&gt;exactly&lt;/em&gt; what we had in the build script: it registers a task, gives it a description, but more importantly, it sets the &lt;em&gt;conventional&lt;/em&gt; values of inputs and outputs.
Note how I used the &lt;code&gt;convention&lt;/code&gt; method to set the input directory, instead of the &lt;code&gt;set&lt;/code&gt; method that we used in the build script: while using both would work, there&amp;#8217;s a semantic difference between the two: in a plugin, you most likely want to set the convention value, which is the value which is used by default, if the user says nothing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Our plugin does one more thing, that we didn&amp;#8217;t cover yet: &lt;em&gt;wiring&lt;/em&gt; the task in the &quot;lifecycle&quot;, as my colleague asked.
The notion of &quot;lifecyle&quot; doesn&amp;#8217;t really make sense in Gradle, and most likely comes from the Maven mindset, where things are defined via a &quot;lifecyle&quot;.
I already covered this topic &lt;a href=&quot;https://melix.github.io/blog/2018/09/gradle-lifecycle.html&quot;&gt;in this blog post&lt;/a&gt;, but here&amp;#8217;s the major difference: in Gradle, &lt;em&gt;everything&lt;/em&gt; declares its inputs, and the tool is responsible for wiring things properly, so that you don&amp;#8217;t have to execute redundant work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, the legitimate question is: my plugin generates some sources, but they need to be compiled, and therefore available to my production code, how can I do that?
This is where the &lt;code&gt;JavaPluginExtension&lt;/code&gt; comes into play.
In fact, our plugin doesn&amp;#8217;t work independently: it assumes that we&amp;#8217;re programming Java, and it assumes that we can compile Java sources.
For this, we can actually make the assumption &lt;em&gt;explicit&lt;/em&gt;, by requiring that the &lt;code&gt;JavaPlugin&lt;/code&gt; is applied.
When this plugin is applied, it defines a &lt;code&gt;JavaPluginExtension&lt;/code&gt;, which declares source sets.
In particular, it defines the Java source sets (&lt;code&gt;main&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;), which are the sources which are compiled.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The shift in mindset is, therefore, not to wonder how to compile the generated sources and put them &quot;on the classpath&quot;, like &lt;a href=&quot;https://melix.github.io/blog/2021/10/gradle-quickie-dependson.html&quot;&gt;you&amp;#8217;d do in Maven&lt;/a&gt;, but simply explain that there&amp;#8217;s another directory of sources to consider.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is exactly what our plugin is doing:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;javaExt.getSourceSets()
    .getByName(SourceSet.MAIN_SOURCE_SET_NAME)
    .getJava()
    .srcDir(generateLexer);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This says &quot;please add the output of the &lt;code&gt;generateLexer&lt;/code&gt; task as a source directory&quot;.
Which is semantically much more powerful.
The magic is that because the &lt;code&gt;generateLexer&lt;/code&gt; task defines an output directory, now we just said that this output directory contains Java classes.
And &lt;em&gt;any&lt;/em&gt; task which requires Java sources will automatically trigger the execution of our &lt;code&gt;generateLexer&lt;/code&gt; task: we don&amp;#8217;t have to define the relationship explicitly!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Outcome #2&lt;/strong&gt;: Gradle models relationships using domain objects which are shared between plugins. It can &lt;em&gt;infer&lt;/em&gt; dependencies thanks to those objects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In other words, &lt;em&gt;because&lt;/em&gt; the input of the Java compilation task is a &lt;em&gt;source set&lt;/em&gt;, and that source set defines that as an input, it has a directory which is generated by the &lt;code&gt;generateLexer&lt;/code&gt; task, Gradle knows that before compiling, it needs to call that &lt;code&gt;generateLexer&lt;/code&gt; task.
Any other task using the source set as an input will do the same: it avoids duplication of code and hard wiring!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_using_the_worker_api&quot;&gt;Using the worker API&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, we&amp;#8217;re pretty much done with the wiring, but we still miss the actual implementation of the task.
This could be left as an exercise to the reader, but there&amp;#8217;s actually an interesting aspect of the Gradle APIs to cover.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you remember, I mentioned in the introduction of the blog post that the JFlex API uses a mix of static state and instance state to configure itself.
This isn&amp;#8217;t nice, as it basically means that the API is not thread-safe: if, for some reason, we have multiple tasks generating sources (for example if we have multiple jflex directories, or different projects having jflex sources), then we can&amp;#8217;t safely generate sources in parallel!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is quite problematic, but Gradle provides a simple workaround for this: the &lt;a href=&quot;https://docs.gradle.org/current/userguide/worker_api.html&quot;&gt;worker API&lt;/a&gt;.
The worker API allows a number of things, but in particular it permits executing code in a different process, or, more lightweight, in an isolated classloader.
The second option is good for us, because &lt;em&gt;static state&lt;/em&gt; in Java is only as static as it is in a given classloader: if 2 &quot;identical&quot; classes are loaded in 2 different classloaders, then they both have their independent static state.
We&amp;#8217;re going to use this to properly isolate execution of our code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, executing JFlex will be slightly more complicated, but as usual in programming, it&amp;#8217;s only &lt;em&gt;one level of indirection&lt;/em&gt;.
Instead of having our task directly invoke JFlex, we need to create a class which is going to invoke JFlex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To use the worker API, we need to inject the so-called &lt;code&gt;WorkerExecuter&lt;/code&gt; in our task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;jflex-plugin/src/main/java/io/micronaut/internal/jflex/JFlexTask.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@CacheableTask
public abstract class JFlexTask extends DefaultTask {

    @InputDirectory
    @PathSensitive(PathSensitivity.RELATIVE)
    public abstract DirectoryProperty getSourceDirectory();

    @OutputDirectory
    public abstract DirectoryProperty getOutputDirectory();

    @Inject
    protected abstract WorkerExecutor getWorkerExecutor();

    @TaskAction
    public void generateSources() {
        // We&apos;re using classloader isolation, because the JFlex API
        // uses static state!
        getWorkerExecutor()
                .classLoaderIsolation()
                .submit(JFlexAction.class, params -&amp;gt; {
                    params.getSourceDirectory().set(getSourceDirectory());
                    params.getSourceFiles().from(getSourceDirectory());
                    params.getOutputDirectory().set(getOutputDirectory());
                });
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note again how you don&amp;#8217;t need to care &lt;em&gt;how&lt;/em&gt; to get a &lt;code&gt;WorkerExecuter&lt;/code&gt;: just tell Gradle you need it and voilà!
When using the worker API, the task action basically becomes an empty shell, which just configures how actual execution should happen.
In this case, we declare &lt;em&gt;classloader isolation&lt;/em&gt;, as well as the inputs of the &lt;em&gt;action&lt;/em&gt;, which is going to be executed in isolation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The action class basically consists of calling the JFlex API:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;jflex-plugin/src/main/java/io/micronaut/internal/jflex/JFlexAction.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public abstract class JFlexAction implements WorkAction&amp;lt;JFlexAction.Parameters&amp;gt; {
    public interface Parameters extends WorkParameters {
        DirectoryProperty getSourceDirectory();
        ConfigurableFileCollection getSourceFiles();
        DirectoryProperty getOutputDirectory();
    }

    @Override
    public void execute() {
        OptionUtils.setDefaultOptions();
        Path sourcePath = getParameters().getSourceDirectory().getAsFile().get().toPath();
        File outputDirectory = getParameters().getOutputDirectory().getAsFile().get();
        OptionUtils.setDir(outputDirectory);
        Options.dump = false;
        Options.encoding = StandardCharsets.UTF_8;
        Options.no_backup = true;
        getParameters().getSourceFiles()
                .getAsFileTree()
                .getFiles()
                .forEach(jflexFile -&amp;gt; generateSourceFileFor(jflexFile, outputDirectory, sourcePath));
    }

    private void generateSourceFileFor(File jflexFile, File outputDirectory, Path sourcePath) {
        String relativePath = sourcePath.relativize(jflexFile.getParentFile().toPath()).toString();
        OptionUtils.setDir(new File(outputDirectory, relativePath));
        new LexGenerator(jflexFile).generate();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The action declares its inputs with the &lt;code&gt;WorkParameters&lt;/code&gt; interface and the code which is going to be executed in an isolated classloader lives in the &lt;code&gt;execute&lt;/code&gt; method.
You can see how it uses static state (&lt;code&gt;OptionsUtils.setDefaultOptions()&lt;/code&gt;, &lt;code&gt;Options.dump&lt;/code&gt;, &amp;#8230;&amp;#8203;).
The worker API lets us workaround what should probably be considered as a &lt;em&gt;bug&lt;/em&gt; in JFlex!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Outcome #3&lt;/strong&gt;: The Gradle Worker API lets you isolate your task code in classloaders or even separate worker processes.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_more_about_the_provider_api&quot;&gt;More about the provider API&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before closing this blog post, I want to give you a bit more insights about the provider API.
I already mentioned that one of the main advantages is that it solves ordering issues, by being fully lazy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the most interesting aspects of this API is &lt;em&gt;value derivation&lt;/em&gt;.
To understand this concept, let&amp;#8217;s imagine a &lt;em&gt;Greeter&lt;/em&gt; task which is responsible for saying hello:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;abstract class Greeter extends DefaultTask {
    @Input
    public abstract Property&amp;lt;String&amp;gt; getUser()

    @Input
    public abstract Property&amp;lt;String&amp;gt; getIntro()

    @Input
    public abstract Property&amp;lt;String&amp;gt; getOutro()

    @TaskAction
    public void sayHello() {
        String user = getUser().get();
        String intro = getIntro().get();
        String outro = getOutro().get();
        System.out.println(intro + user + outro);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;we can register a task which says hello in English by doing this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;sayHello&quot;, Greeter) {
   intro = &quot;Hello, &quot;
   user = &quot;Cédric&quot;
   outro = &quot;!&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And another one which says hello in French:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&quot;direBonjour&quot;, Greeter) {
   intro = &quot;Bonjour &quot;
   user = &quot;Cédric&quot;
   outro = &quot; !&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s a bit annoying that we have to repeat the user declaration in both tasks, and the rule &quot;in french, exclamation mark must be preceeded with a space&quot; doesn&amp;#8217;t need to be known to the user.
To avoid this redundancy, we&amp;#8217;re going to write a plugin which makes all this more convenient.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, we&amp;#8217;re going to create an &lt;em&gt;extension&lt;/em&gt;, which is going to hold what is &lt;em&gt;relevant&lt;/em&gt; for user configuration: the name of the person to greet and what outro we want to use.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;interface GreetingExtension {
    Property&amp;lt;String&amp;gt; getUser()
    Property&amp;lt;String&amp;gt; getOutro()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again we don&amp;#8217;t have to provide an implementation for this, Gradle knows how to create a &lt;code&gt;Property&amp;lt;String&amp;gt;&lt;/code&gt;. This extension simply needs to be created by our plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;GreetingExtension extension = project.getExtensions().create(&quot;greeting&quot;, GreetingExtension.class);
extension.getOutro().convention(&quot;!&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s interesting to see that our DSL will only expose &quot;user&quot; and &quot;outro&quot;, but not the intro, which is actually dependent on the language.
We can also set a conventional value on the extension itself.
The plugin can then register both tasks for us:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;tasks.register(&quot;sayHello&quot;, Greeter.class, task -&amp;gt; {
   task.getIntro().convention(&quot;Hello, &quot;);
   task.getUser().convention(extension.getUser());
   task.getOutro().convention(extension.getOutro());
});
tasks.register(&quot;direBonjour&quot;, Greeter.class, task -&amp;gt; {
   task.getIntro().convention(&quot;Bonjour &quot;);
   task.getUser().convention(extension.getUser());
   task.getOutro().convention(extension.getOutro().map(o -&amp;gt; &quot; &quot; + o));
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you see the interest of using the provider API: for the english case, the task is going to use the outro value &lt;em&gt;directly&lt;/em&gt;, while for the french version, by default, it&amp;#8217;s going to compute a &lt;em&gt;derived&lt;/em&gt; value.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The user will configure the tasks via the extension:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;greeting {
    user = &quot;Cédric&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Calling &lt;code&gt;sayHello&lt;/code&gt; will output:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;exampleblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hello, Cédric!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While calling &lt;code&gt;direBonjour&lt;/code&gt; will output:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;exampleblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bonjour Cédric !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Should the user configure a different outro, the outputs would be different:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;greeting {
    user = &quot;Cédric&quot;
    outro = &quot;!!!&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;results in this english version:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;exampleblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hello, Cédric!!!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While the french one is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;exampleblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bonjour Cédric !!!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;BUT, because we defined the &lt;em&gt;convention value&lt;/em&gt; of outro of the french task as a derived value, it is still possible for the user to override it completely:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;greeting {
    user = &quot;Cédric&quot;
    outro = &quot;!!!&quot;
}
tasks.named(&quot;direBonjour&quot;) {
    outro = &quot; !&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then executing &lt;code&gt;direBonjour&lt;/code&gt; would print:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;exampleblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bonjour Cédric !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Outcome #4&lt;/strong&gt;: The provider API lets precisely define how to compute a value from another property, in a lazy manner, and provides an elegant way to supply default, or conventional values.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can read more about lazy configuration and the provider API in the &lt;a href=&quot;https://docs.gradle.org/current/userguide/lazy_configuration.html&quot;&gt;Gradle documentation&lt;/a&gt;, but in a nutshell, the derivation logic is &lt;em&gt;exactly&lt;/em&gt; what the &lt;code&gt;layout.buildDirectory.dir(&quot;&amp;#8230;&amp;#8203;&quot;)&lt;/code&gt; is doing: it defines a directory which is &lt;em&gt;derived from&lt;/em&gt; the existing build directory value.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, we&amp;#8217;ve leveraged a real world use case, integrating lexer generation via JFlex, to explain how to properly write a Gradle plugin which:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;uses the lazy provider API, making it immune to configuration ordering problems&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;explains how Gradle&amp;#8217;s &quot;task dependencies&quot; are &lt;em&gt;implicit&lt;/em&gt;, avoiding hardcoding relationships between tasks, and making it much more robust to arbitrary configuration changes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;doesn&amp;#8217;t rely on arbitrary ordering (e.g, like in Maven, &quot;&lt;em&gt;all&lt;/em&gt; sources of &lt;em&gt;all&lt;/em&gt; generators must be generated before you can compile &lt;em&gt;anything&lt;/em&gt;&quot;) but instead knows that &lt;em&gt;only&lt;/em&gt; if you need to compile the main source set, &lt;em&gt;then&lt;/em&gt; you need to generate JFlex sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;uses the worker API, letting us working around a bug in the JFlex library regarding shared mutable state&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, we&amp;#8217;ve seen the basics of the provider API, which allows plugins to define default values as well as computing derived values for inputs or outputs in a lazy manner.
We&amp;#8217;ve also hinted at how plugins can expose configuration mechanisms which reduce the API surface, while making it convenient to refactor, therefore dramatically reducing the cost of maintenance of builds.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, the &lt;em&gt;user facing code&lt;/em&gt; of using our JFlex plugin is a &lt;em&gt;single line&lt;/em&gt; in a build script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &quot;io.micronaut.internal.jflex&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There is &lt;em&gt;no configuration&lt;/em&gt; (because we use the convention values) and &lt;em&gt;no imperative code&lt;/em&gt; (because the build logic of creating tasks is deferred to a &lt;em&gt;plugin&lt;/em&gt;).
As a bonus, because we used a &lt;em&gt;separate build&lt;/em&gt; and &lt;a href=&quot;https://docs.gradle.org/current/userguide/composite_builds.html&quot;&gt;composite builds&lt;/a&gt;, if we want to publish this plugin to the Gradle plugin portal later, it would be just about adding some configuration to the &lt;code&gt;jflex-plugin&lt;/code&gt; module.
There is effectively no need to publish a plugin, either to a local repository, or a remote one, to be able to use plugins in Gradle!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The full code is actually available in the upcoming &lt;a href=&quot;https://github.com/micronaut-projects/micronaut-toml&quot;&gt;Micronaut TOML module&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Composition over inheritance: Gradle vs Maven</title>
      <link>https://melix.github.io/blog//2021/12/composition-in-gradle.html</link>
      <pubDate>Wed, 1 Dec 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/12/composition-in-gradle.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In general, when I read comments about Maven vs Gradle, I realize that people focus on the cosmetics (XML vs Groovy/Kotlin) when it&amp;#8217;s from my point of view the least interesting aspect of the comparison.
In this article, I want to focus on one particular aspect which differentiates the 2 build tools: the famous &lt;strong&gt;composition over inheritance&lt;/strong&gt; paradigm.
In different aspects (POM files, lifecycle), Apache Maven is using &lt;em&gt;inheritance&lt;/em&gt;, while Gradle is using &lt;em&gt;composition&lt;/em&gt;.
It is a particularly important difference which completely changes the way we think about building software.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_inheritance_in_maven_builds&quot;&gt;Inheritance in Maven builds&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A typical Maven project is built with a &lt;em&gt;pom.xml&lt;/em&gt; file, which declares everything the module needs:
- the dependencies
- the build plugins and their configuration&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Very quickly, it turns out that there are &lt;em&gt;common things&lt;/em&gt; that you want to share between modules:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;they would use the same compiler options&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;they would use the same plugins and configuration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;they would apply a number of common dependencies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;etc.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s imagine that we have a project which consists of 3 modules:
- a &lt;code&gt;library&lt;/code&gt; module, pure Java
- an &lt;code&gt;application&lt;/code&gt; module which uses the &lt;code&gt;library&lt;/code&gt; and the &lt;a href=&quot;https://micronaut.io&quot;&gt;Micronaut Framework&lt;/a&gt;
- and a &lt;code&gt;documentation&lt;/code&gt; module which provides a user manual for the application using &lt;a href=&quot;https://asciidoctor.org&quot;&gt;Asciidoctor&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idiomatic way to solve the problem of sharing the configuration of the &lt;code&gt;library&lt;/code&gt; and &lt;code&gt;application&lt;/code&gt; modules (which are both Java) in Maven is to define a so-called &quot;parent POM&quot; which declares all of these common things, for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;project xmlns=&quot;https://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

    &amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;example-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;

    &amp;lt;name&amp;gt;Common Config&amp;lt;/name&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;java.version&amp;gt;1.8&amp;lt;/java.version&amp;gt;
        &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;
        &amp;lt;junit.jupiter.version&amp;gt;5.8.1&amp;lt;/junit.jupiter.version&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.junit.jupiter&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;junit-jupiter&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${junit.jupiter.version}&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-surefire-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;3.0.0-M5&amp;lt;/version&amp;gt;
            &amp;lt;/plugin&amp;gt;

            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;source&amp;gt;${java.version}&amp;lt;/source&amp;gt;
                    &amp;lt;target&amp;gt;1.8&amp;lt;/target&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To simplify things, we could call this a &quot;convention&quot;: by convention, all modules which will use this parent POM will apply all those plugins and dependencies (note, there are subtleties if you use &lt;code&gt;&amp;lt;pluginManagement&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;dependencyManagement&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A &quot;child POM&quot; like our application pom only has to declare the parent to &quot;inherit&quot; from it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;project xmlns=&quot;https://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;https://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

    &amp;lt;parent&amp;gt;
        &amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;example-parent&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;1.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
    &amp;lt;/parent&amp;gt;

    &amp;lt;artifactId&amp;gt;application&amp;lt;/artifactId&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;library&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.0.0-SNAPSHOT&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;

&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This model works really well when all modules have a lot in common.
The inheritance model also makes it simple to override things (child values override parent values).
In the example above, we don&amp;#8217;t have to specify the &lt;code&gt;groupId&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt; of our module because it will be inherited from the parent.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, this model comes with a number of drawbacks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;as soon as you have different modules which share different set of dependencies, or use different sets of plugins, you have to create different parents and have an inheritance model between parents. Unfortunately this is the case here, since only our &lt;code&gt;library&lt;/code&gt; and &lt;code&gt;application&lt;/code&gt; modules have something in common. It won&amp;#8217;t be a surprise for many that you have to &lt;em&gt;exclude dependencies&lt;/em&gt; just because they came through parent poms&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you can only have a &lt;em&gt;single&lt;/em&gt; parent, meaning that you cannot inherit from a framework parent POM &lt;em&gt;and&lt;/em&gt; from your own conventions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it&amp;#8217;s not great for performance, because you end up configuring a lot of things which will never be necessary for your particular &quot;child&quot; module.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;overriding values is sometimes much more complicated and you have to start relying on obscure syntaxes like &lt;code&gt;combine.children=&quot;append&quot;&lt;/code&gt; (see &lt;a href=&quot;https://www.baeldung.com/maven-plugin-override-parent&quot;&gt;this excellent blog post&lt;/a&gt; for details).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those limitations are quickly reached when you are using a framework like &lt;a href=&quot;https://micronaut.io&quot;&gt;Micronaut&lt;/a&gt; or &lt;a href=&quot;https://spring.io/projects/spring-boot&quot;&gt;Spring Boot&lt;/a&gt;.
Because those frameworks are built with developer productivity in mind, they come with their own &quot;parent POMs&quot; which makes the lives of developers easier by avoiding copy and paste of hundreds of lines of XML.
They also need to provide this parent POM because they would come with their own Maven plugin which works around the limitations of the lifecycle model.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But then, we have a problem: on one side, you have this &quot;parent POM&quot; which is provided by the framework, and on the other side, you have your own &quot;parent POM&quot; which is providing, say, the company-specific conventions (like checkstyle configuration, coordinates of Maven repositories for publication, etc.).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In order to be able to use both conventions, you have to create a new parent POM, and you have no choice but writing your company convention parent POM inheriting from the framework POM: obviously you can&amp;#8217;t change the framework POM itself!
This is problematic, because it means that &lt;strong&gt;for every release of the framework, you have to update your company convention parent POM&lt;/strong&gt;.
This is also problematic for another aspect: not all the modules of your multi-project build are &quot;Spring Boot&quot; or &quot;Micronaut&quot; applications.
Some of them may be simple Java libraries which are used by your app, but do &lt;em&gt;not&lt;/em&gt; require the framework. As a consequence, you have to create &lt;em&gt;multiple&lt;/em&gt; parents, and duplicate the configuration in each of those POM files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This inheritance problem surfaces in different places in Maven.
Another one is, as I mentioned, the &quot;lifecycle&quot; which works in phases.
Basically, in Maven everything is executed linearly: if you want to do &lt;em&gt;install&lt;/em&gt;, then you &lt;em&gt;have to&lt;/em&gt; execute everything which is &lt;em&gt;before&lt;/em&gt; that phase, which includes, for example, &lt;em&gt;test&lt;/em&gt;.
This may sound reasonable, but this model completely falls apart: this is no surprise that &lt;em&gt;every single plugin&lt;/em&gt; has to implement their own &lt;code&gt;-DskipTest&lt;/code&gt; variant, in order to avoid doing work which shouldn&amp;#8217;t be done.
I had &lt;a href=&quot;https://lists.apache.org/list?&lt;a href=&quot;mailto:users@maven.apache.org&quot;&gt;users@maven.apache.org&lt;/a&gt;:2021-9&quot;&gt;an interesting use case when implementing the GraalVM native Maven plugin&lt;/a&gt;, which requires to configure the surefire plugin to pass extra arguments.
Long story short: this isn&amp;#8217;t possible with Maven.
Consequence: the only workaround is the multiplication of Maven profiles, which a user has to understand, maintain, and remember.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_composition_in_gradle_builds&quot;&gt;Composition in Gradle builds&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle builds use a very different model: &lt;strong&gt;composition&lt;/strong&gt;.
In a nutshell, in a Gradle project you don&amp;#8217;t explain &lt;em&gt;how to build&lt;/em&gt;, but &lt;em&gt;what you build&lt;/em&gt;: that is, you would say &quot;this is a library&quot;, or &quot;this is a CLI application&quot; or &quot;this is a documentation module&quot;.
Because a library exposes an API and an application doesn&amp;#8217;t, those are &lt;em&gt;different things&lt;/em&gt;, so their conventions, and capabilities, are different.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The way you &quot;say&quot; this is in a Gradle build is by &lt;em&gt;applying plugins&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A typical Java library would apply the &lt;code&gt;java-library&lt;/code&gt; plugin, while an application would apply the &lt;code&gt;application&lt;/code&gt; plugin and a documentation project would apply, say, the &lt;code&gt;asciidoctor&lt;/code&gt; plugin.
What do a Java library project and a documentation project have in common? Barely nothing.
A Java Library has Java sources, a number of dependencies, code quality plugins applied, etc.
The documentation module, on its side, is a set of markdown or asciidoc files, and resources.
The layout of the projects is different, the &lt;em&gt;conventions&lt;/em&gt; are different, and the set of plugins are different.
Java projects may share the same conventions for source layout, but they are obviously different for the docs.
In addition, there&amp;#8217;s &lt;em&gt;no reason&lt;/em&gt; to let the user declare &quot;implementation&quot; dependencies on the documentation project: it doesn&amp;#8217;t make sense so it should be an error to do so.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On the other hand all those modules may share a number of things:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;they are all published to a Maven repository&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;they need to use the same Java toolchain&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;they need to comply to security policies of your company&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The way Gradle solves this problem is by &lt;em&gt;composing plugins&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a plugin can &quot;apply&quot; another plugin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;each plugin is guaranteed to be applied only once, even if several plugins use it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a plugin can &quot;react&quot; to the application of other plugins, allowing fine-grained customizations&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So in the example above, the &lt;code&gt;application&lt;/code&gt; use case can be easily solved:
first, you&amp;#8217;d have your own &quot;convention plugin&quot; which defines your company conventions (e.g apply the &lt;code&gt;checkstyle&lt;/code&gt; plugin with a number of rules).
Then, you&amp;#8217;d have the Micronaut application plugin which is already written for you.
Finally, your application module would simply &lt;em&gt;apply both plugins&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
   id &apos;com.mycompany.conventions&apos; version &apos;1.0.0&apos;
   id &apos;io.micronaut.application&apos; version &apos;3.0.0&apos;
}

micronaut {
    version &apos;3.2.0&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What becomes &lt;em&gt;more interesting&lt;/em&gt; is that you can (and you actually &lt;em&gt;should&lt;/em&gt;)  create your own &quot;component types&quot; which apply a number of plugins.
In the example above, we could replace the use of the 2 plugins with a single one:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
   id &apos;com.mycompany.micronaut-application&apos; version &apos;3.0.0&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note how we moved the configuration of the &lt;code&gt;micronaut&lt;/code&gt; version to our convention plugin.
I&amp;#8217;m not going to explain how to write a custom Gradle plugin in this blog post, but the &lt;em&gt;code&lt;/em&gt; of this plugin would very much look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    id &apos;com.mycompany.conventions&apos; version &apos;1.0.0&apos;
    id &apos;io.micronaut.application&apos; version &apos;3.0.0&apos;
}

micronaut {
    version &apos;3.2.0&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Does it look familiar? Yes it does, this is &lt;em&gt;exactly&lt;/em&gt; what we had in the beginning: composition is slowly happening!
I encourage you to take a look at &lt;a href=&quot;https://docs.gradle.org/current/userguide/structuring_software_products.html&quot;&gt;this documentation&lt;/a&gt; for further details about writing your own convention plugins.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Interestingly, as I said, Gradle plugins are allowed to &lt;em&gt;react&lt;/em&gt; to the presence of other plugins.
This makes it particularly neat for defining dynamically more tasks depending on the context.
For example, a plugin can do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;pluginManager.withPlugin(&apos;io.micronaut.application&apos;) {
    // configure the Micronaut application plugin
}
pluginManager.withPlugin(&apos;io.micronaut.library&apos;) {
    // configure the Micronaut library plugin
}
pluginManager.withPlugin(&apos;io.spring.boot&apos;) {
    // configure the Spring Boot plugin
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Which is very resilient to the fact that the plugins may be applied in any order and that they can combine with each other to provide higher level constructs.
It also makes it possible to &lt;em&gt;give choice&lt;/em&gt; to users regarding their preferences: you provide a single convention plugin which is aware of what to do if the user prefers to use Spring Boot over Micronaut.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, &lt;code&gt;com.mycompany.micronaut-application&lt;/code&gt; is defined as a combination of the &lt;code&gt;io.micronaut.application&lt;/code&gt;, &lt;code&gt;your.company.conventions&lt;/code&gt; plugins.
Instead of declaring &lt;em&gt;how to build&lt;/em&gt; your company application, you simply described &lt;em&gt;what it is&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is only touching the surface of the Gradle world here, but when I read that Gradle is &quot;just Ant on steroids&quot;, &lt;strong&gt;nothing could be more wrong&lt;/strong&gt;.
Gradle in this case is much superior, because it focuses on &lt;em&gt;convention over configuration&lt;/em&gt;, while providing better constructs than Maven does for it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But let&amp;#8217;s come back to our multi-project example: each of the modules would apply a different convention plugin (which is also why it&amp;#8217;s important that the &lt;em&gt;allprojects&lt;/em&gt; pattern dies):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;library&lt;/code&gt; would apply the &lt;code&gt;com.mycompany.library&lt;/code&gt; plugin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;application&lt;/code&gt; would apply the &lt;code&gt;com.mycompany.application&lt;/code&gt; plugin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;docs&lt;/code&gt; would apply the &lt;code&gt;com.mycompany.docs&lt;/code&gt; plugin&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;com.mycompany.library&lt;/code&gt; plugin would, for example, apply the &lt;code&gt;java-library&lt;/code&gt; and &lt;code&gt;com.mycompany.java-conventions&lt;/code&gt; plugin.
The &lt;code&gt;com.mycompany.application&lt;/code&gt; plugin would, for example, apply the &lt;code&gt;io.micronaut.application&lt;/code&gt; and &lt;code&gt;com.mycompany.java-conventions&lt;/code&gt; plugin (knowing that the &lt;code&gt;io.micronaut.application&lt;/code&gt; plugin applied the &lt;code&gt;application&lt;/code&gt; plugin and more, such as the GraalVM plugin)
The &lt;code&gt;com.mycompany.docs&lt;/code&gt; plugin would, for example, apply the &lt;code&gt;org.asciidoctor.jvm.convert&lt;/code&gt; plugin and the &lt;code&gt;com.mycompany.docs&lt;/code&gt; plugin.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll notice how those actually combine together, making it easier to maintain and upgrade builds: should you change the company conventions, all you have to do is release a new version of the convention plugin.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this quickie, I have explained a major difference in how Maven and Gradle envision build configuration.
While both of them are designed with &lt;em&gt;convention over configuration&lt;/em&gt; in mind, the inheritance model of Maven makes it difficult to build conventions on top of each other without duplication.
On the other hand, Gradle uses a &lt;em&gt;composition&lt;/em&gt; model which makes it possible to design your own conventions while being aware of other plugins being applied by the user: Gradle builds are more lenient and more maintainable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a complement, you might be interested in:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;reading the &lt;a href=&quot;https://docs.gradle.org/current/userguide/structuring_software_products.html&quot;&gt;structuring large projects&lt;/a&gt; documentation from the Gradle docs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;watching my &lt;a href=&quot;https://www.youtube.com/watch?v=MaansFoPHKg&amp;amp;feature=youtu.be&quot;&gt;10 mins video&lt;/a&gt; about authoring Gradle builds&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;following my former team mate Jendrik who created &lt;a href=&quot;https://www.youtube.com/playlist?list=PLWQK2ZdV4Yl2k2OmC_gsjDpdIBTN0qqkE&quot;&gt;a series of videos about modern Gradle&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Multi-repository development made easy</title>
      <link>https://melix.github.io/blog//2021/11/multirepo-dev-made-easy.html</link>
      <pubDate>Thu, 4 Nov 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/11/multirepo-dev-made-easy.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_are_you_working_in_a_multi_repository_setup&quot;&gt;Are you working in a multi-repository setup?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In general, things start getting messy as soon as you have a feature which requires changes to more than one repository.
For example, you may have a &lt;code&gt;core&lt;/code&gt; repository, and a &lt;code&gt;module&lt;/code&gt; repository, and the feature that you&amp;#8217;re working on for &lt;code&gt;module&lt;/code&gt; requires API changes in &lt;code&gt;module&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If so, it&amp;#8217;s likely that you&amp;#8217;ve been annoyed by the fact that to be able to test the changes to &lt;code&gt;module&lt;/code&gt;, you minimally had to publish a local snapshot to your local Maven repository.
While this can kind of work locally, it&amp;#8217;s easy to miss publishing from time to time, and therefore thinking that a change works when it actually relies on an outdated dependency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Things get more complicated as soon as CI is involved, or that you want to share the results of work in progress, for example for review, with your colleagues:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;did you ever had to explain that they had to checkout &lt;code&gt;core/some-branch&lt;/code&gt;, publish to Maven local, then checkout &lt;code&gt;module/some-feature-branch&lt;/code&gt; and test it?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;did you ever realize late that you forgot to push changes to &lt;code&gt;master&lt;/code&gt; so that they could try?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;did you ever complain that to make this happen on CI, you actually had to &lt;em&gt;eagerly merge&lt;/em&gt; your feature branch to &lt;code&gt;core&lt;/code&gt;, just so that the other repository, on a &lt;em&gt;feature branch&lt;/em&gt;, could see it?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;did you ever want to see if your modules simply do not break with latest &lt;em&gt;master&lt;/em&gt;, without having to change anything to your build scripts?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you answered yes to any of those questions, then I&amp;#8217;m glad to say &lt;strong&gt;there&amp;#8217;s a solution!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The underlying problem is that using Maven SNAPSHOTs to deal with multi-repository development is not a good enough.
It cannot model the complexity of multi-repository development, with features being developed concurrently on different branches.
Using SNAPSHOTs (binary dependencies) to coordinate projects leads to hard to diagnose bugs, broken integration processes.
You typically have to eagerly push changes, or wait for snapshots to be published on a shared repository, just so that you can actually verify that integration with other modules work.
Those problems do not happen in a a &lt;em&gt;single repository&lt;/em&gt; world, because all changes are integrated at once.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I faced this very same problem with Micronaut:I&amp;#8217;m currently working on a feature which involves changes to multiple repositories at once:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/micronaut-projects/micronaut-core/&quot;&gt;Micronaut Core&lt;/a&gt;, with additional public APIs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/micronaut-projects/micronaut-aot/&quot;&gt;Micronaut AOT&lt;/a&gt;, the new module I&amp;#8217;m actively working on&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/micronaut-projects/micronaut-gradle-plugin/&quot;&gt;the Micronaut Gradle Plugin&lt;/a&gt;, which integrates the AOT module&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and a local test project which uses the modified Gradle plugin&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s, minimally 4 different projects, and a change to any of them is a pain to deal with.
With my experience with Gradle, I &lt;em&gt;knew&lt;/em&gt; there was a better way.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_plugin_to_make_it_easier&quot;&gt;A plugin to make it easier!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today, I&amp;#8217;m happy to announce a new Gradle plugin which aims at making multi-repository development a breeze: &lt;a href=&quot;https://melix.github.io/includegit-gradle-plugin&quot;&gt;Included Git repositories plugin&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This plugin lets you &lt;em&gt;import Git repositories&lt;/em&gt; as source dependencies, without having to change your dependency declarations.
What does that mean?
In the example above, it means that I can explain, when I&amp;#8217;m working on &lt;code&gt;module&lt;/code&gt;, that it needs to build against &lt;code&gt;core/some-branch&lt;/code&gt;: Gradle will then automatically checkout the project, build the branch and &lt;em&gt;substitute&lt;/em&gt; any binary dependency corresponding to &lt;code&gt;core&lt;/code&gt; with the source dependency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, the configuration would look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;gitRepositories {
	include(&apos;core&apos;) {
		uri = &apos;git@github.com:mycompany/core.git&apos;
		branch = &apos;some-branch&apos;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s it! No need to change your build scripts to update dependency coordinates, Gradle will do the magic!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It completely changes the way of thinking about multi-repository development, because CI, or colleagues, would not have to care about instructions about how to build your particular branch: everything is known upfront.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, you&amp;#8217;re going to tell that well, that&amp;#8217;s cool but it still requires you to push your changes to the remote repository so that you can test things &lt;em&gt;locally&lt;/em&gt;.
Well, a good multi-repository development story must integrate both the &lt;em&gt;local&lt;/em&gt; and &lt;em&gt;remote&lt;/em&gt; experience.
This is why this plugin actually makes it a breeze to support this pattern.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are actually 2 ways you can handle this.
The first one is to explain to Gradle that instead of checking out the sources, it can simply use a local copy instead.
In this case, the plugin will simply &lt;em&gt;ignore&lt;/em&gt; whatever you declared in the &lt;code&gt;gitRepositories&lt;/code&gt; block for the repository, and use whatever is available locally.
For this you&amp;#8217;d set a &lt;code&gt;local.git.&amp;lt;repoName&amp;gt;&lt;/code&gt; Gradle property (in your &lt;code&gt;gradle.properties&lt;/code&gt; file) pointing to your local copy.
In the example above, I would for example add a &lt;code&gt;local.git.core&lt;/code&gt; property pointing to my local copy of &lt;code&gt;core&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alternatively, if you keep things organized into checkout directories like I do, it&amp;#8217;s likely that you have all your &lt;code&gt;micronaut&lt;/code&gt; related projects in a single &lt;code&gt;micronaut-projects&lt;/code&gt; directory.
In this case, by setting the &lt;code&gt;auto.include.git.dirs&lt;/code&gt; Gradle property to the &lt;code&gt;micronaut-projects&lt;/code&gt; directory, the plugin will automatically map directory names in that &lt;code&gt;micronaut-projects&lt;/code&gt; directory to included Git repository names.
So if I have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;gitRepositories {
	include(&apos;micronaut-core&apos;) {
		uri = &apos;git@github.com:mycompany/core.git&apos;
		branch = &apos;some-branch&apos;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and a &lt;code&gt;micronaut-core&lt;/code&gt; directory under &lt;code&gt;micronaut-projects&lt;/code&gt;, then it will automatically be used instead of cloned from remote.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those options make it extremely convenient to develop locally, and only push changes when ready.
On CI, builds would checkout the dependents automatically, and you&amp;#8217;d have nothing to configure.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_more_complex_use_cases&quot;&gt;More complex use cases&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The very same mechanism can be used to create &quot;integration&quot; builds on CI.
For example, it makes it very simple to have builds which would automatically build against the latest state of &lt;code&gt;master&lt;/code&gt;, instead of having to wait for &lt;code&gt;SNAPSHOT&lt;/code&gt; to be published, and more importantly, without having to change any build file.
As a bonus, it also works for &lt;em&gt;transitive dependencies&lt;/em&gt;: for example if you have A --depends on-&amp;#8594; B --depends on-&amp;#8594; C, then you may want to make sure that if &lt;code&gt;C&lt;/code&gt; is changed, &lt;code&gt;A&lt;/code&gt; still works. How do you do this with snapshots, if there&amp;#8217;s no direct dependency between &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt;? This plugin makes it very simple to test: just declare a Git repository for C and you&amp;#8217;re done!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_need_your_help&quot;&gt;Need your help!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think this plugin has potential to dramatically change how we develop in the multi-repository world.
The plugin is in very early stages, and I will need your help: report bugs, improve the documentation, improve testing, etc.
It will also be interesting to get your user stories so that we, collectively, can improve it to support more scenarios.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Plugin documentation: &lt;a href=&quot;https://melix.github.io/includegit-gradle-plugin&quot; class=&quot;bare&quot;&gt;https://melix.github.io/includegit-gradle-plugin&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Plugin development home: &lt;a href=&quot;https://github.com/melix/includegit-gradle-plugin&quot; class=&quot;bare&quot;&gt;https://github.com/melix/includegit-gradle-plugin&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Plugin on Gradle plugin portal: &lt;a href=&quot;https://plugins.gradle.org/plugin/me.champeau.includegit&quot; class=&quot;bare&quot;&gt;https://plugins.gradle.org/plugin/me.champeau.includegit&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A Gradle quickie: properly using dependsOn</title>
      <link>https://melix.github.io/blog//2021/10/gradle-quickie-dependson.html</link>
      <pubDate>Wed, 6 Oct 2021 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2021/10/gradle-quickie-dependson.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today I&amp;#8217;d like to share a small example of what &lt;em&gt;not to do&lt;/em&gt; with Gradle.
Some of you may already know that I recently joined the &lt;a href=&quot;https://micronaut.io/&quot;&gt;Micronaut team at Oracle&lt;/a&gt;, and part of my job is to improve the build experience, be it for Micronaut itself or Micronaut users.
Today I&amp;#8217;m going to focus on an example I found in the Micronaut build itself.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;TL/DR&lt;/strong&gt;: If you use &lt;code&gt;dependsOn&lt;/code&gt;, you&amp;#8217;re likely doing it wrong.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_when_should_you_use_dependson&quot;&gt;When should you use dependsOn?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, Gradle works by computing a graph of task dependencies.
Say that you want to build a JAR file: you&amp;#8217;re going to call the &lt;code&gt;jar&lt;/code&gt; task, and Gradle is going to determine that to build the jar, it needs to compile the classes, process the resources, etc&amp;#8230;&amp;#8203;
Determining the &lt;em&gt;task dependencies&lt;/em&gt;, that is to say what other tasks need to be executed, is done by looking up at 3 different things:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;the task &lt;code&gt;dependsOn&lt;/code&gt; dependencies. For example, &lt;code&gt;assemble.dependsOn(jar)&lt;/code&gt; means that if you run &lt;code&gt;assemble&lt;/code&gt;, then the &lt;code&gt;jar&lt;/code&gt; task must be executed before&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the task &lt;em&gt;transitive dependencies&lt;/em&gt;, in which case we&amp;#8217;re not talking about tasks, but &quot;publications&quot;. For example, when you need to compile project &lt;code&gt;A&lt;/code&gt;, you need on classpath project &lt;code&gt;B&lt;/code&gt;, which implies running &lt;em&gt;some&lt;/em&gt; tasks of &lt;code&gt;B&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and last but not least, the &lt;em&gt;task inputs&lt;/em&gt;, that is to say, what it needs to execute its work&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In practice, it&amp;#8217;s worth noting that 2. is a subset of 3. but I added it for clarity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s look at this snippet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;gradle&quot;&gt;task docFilesJar(type: Jar, description: &apos;Package up files used for generating documentation.&apos;) {
    archiveVersion = null
    archiveFileName = &quot;grails-doc-files.jar&quot;
    from &quot;src/main/template&quot;
    doLast {
        copy {
            from docFilesJar.archivePath
            into &quot;${buildDir}/classes/groovy/main&quot;
        }
    }
}

jar.dependsOn docFilesJar&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, let&amp;#8217;s realize that this snippet is &lt;em&gt;years old&lt;/em&gt;. I mean, very years old, copied from Grails, which was using early releases of Gradle.
Yet, there&amp;#8217;s something interesting in what it does, which is a &lt;strong&gt;typical mistake I see in all builds I modernize&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s tempting, especially when you&amp;#8217;re not used to Gradle, to think the same way as other build tools do, like Maven or Ant.
You&amp;#8217;re thinking &quot;there&amp;#8217;s a task, jar, which basically packages everything it finds in &lt;code&gt;classes/groovy/main&lt;/code&gt;, so if I want to add more stuff to the jar task, let&amp;#8217;s put more stuff in `classes/groovy/main`&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;This is wrong!&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is wrong for different reasons, most notably:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;when the &lt;code&gt;docsFilesJar&lt;/code&gt; task is going to be executed, it will contribute more files to the &quot;classes&quot; directory, but, wait, those are not classes that we&amp;#8217;re putting in there, right? It&amp;#8217;s just a jar, resources. Shouldn&amp;#8217;t we use &lt;code&gt;resources/groovy/main&lt;/code&gt; instead? Or is it &lt;code&gt;classes/groovy/resources&lt;/code&gt;? Or what? Well, you &lt;strong&gt;shoudn&amp;#8217;t care&lt;/strong&gt; because it&amp;#8217;s not your concern where the Java compile task is going to put its output!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it breaks &lt;em&gt;cacheability&lt;/em&gt;: Gradle has a &lt;em&gt;build cache&lt;/em&gt;, and multiple tasks contributing to the same output directory is the typical example of what would break caching. In fact, it breaks all kinds of up-to-date checking, that is to say the ability for Gradle to understand that it doesn&amp;#8217;t need to execute a task when nothing changed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it&amp;#8217;s opaque to Gradle: the code above executes a copy in a &lt;code&gt;doLast&lt;/code&gt; block. Nothing tells Gradle that the &quot;classes&quot; have additional output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;imagine another task which needs the &lt;code&gt;classes&lt;/code&gt; only. Depending on when it executes, it &lt;em&gt;may&lt;/em&gt; or may not, include the &lt;code&gt;docsFileJar&lt;/code&gt; that it doesn&amp;#8217;t care about. This makes builds non-reproducible (note that this is exactly the reason why Maven build cannot be trusted and that you need to run &lt;code&gt;clean&lt;/code&gt;, because any &quot;goal&quot; can write to any directory at any time, making it impossible to infer who contributed what).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it requires to declare an &lt;em&gt;explicit dependency&lt;/em&gt; between the &lt;code&gt;jar&lt;/code&gt; task and the &lt;code&gt;docsFileJar&lt;/code&gt; task, to make sure that if we execute &lt;code&gt;jar&lt;/code&gt;, our &quot;docs jar&quot; file is present&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it doesn&amp;#8217;t tell &lt;em&gt;why&lt;/em&gt; there&amp;#8217;s a dependency: is it because you want to &lt;em&gt;order&lt;/em&gt; things, or is it because you require an &lt;em&gt;artifact&lt;/em&gt; produced by the dependent task? Something else?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it&amp;#8217;s easy to forget about those: because you may run &lt;code&gt;build&lt;/code&gt; often, you might think that your build works, because &lt;code&gt;jar&lt;/code&gt; is part of the task graph, and &lt;em&gt;by accident&lt;/em&gt;, the &lt;code&gt;docsFileJar&lt;/code&gt; would be executed before&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it creates accidental extra work: most often a &lt;code&gt;dependsOn&lt;/code&gt; will trigger too much work. Gradle is a smart build tool which can compute &lt;em&gt;precisely&lt;/em&gt; what it needs to execute for each specific task. By using &lt;code&gt;dependsOn&lt;/code&gt;, you&amp;#8217;re a bit using a hammer and forcing it to integrate something in the graph which wasn&amp;#8217;t necessarily needed. In short: you&amp;#8217;re doing too much work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it&amp;#8217;s difficult to get rid of them: when you see a &lt;code&gt;dependsOn&lt;/code&gt;, because it doesn&amp;#8217;t tell &lt;em&gt;why&lt;/em&gt; it&amp;#8217;s needed, it&amp;#8217;s often hard to get rid of such dependencies when optimizing builds&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_use_implicit_dependencies_instead&quot;&gt;Use implicit dependencies instead!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The answer to our problem is actually simpler to reason about: reverse the logic.
Instead of thinking &quot;where should I put those things so that it&amp;#8217;s picked up by jar&quot;, think &quot;let&amp;#8217;s tell the &lt;code&gt;jar&lt;/code&gt; task that it also needs to pick up my resources&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All in all, it&amp;#8217;s about &lt;em&gt;properly declaring your task inputs&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Instead of patching up the output of another task (seriously, forget about this!), every single task must be thought as a function which takes inputs and produces an output: it&amp;#8217;s &lt;strong&gt;isolated&lt;/strong&gt;.
So, what are the inputs of our &lt;code&gt;docsFileJar&lt;/code&gt;? The resources we want to package. What are its outputs? The &lt;code&gt;jar&lt;/code&gt; itself. There&amp;#8217;s &lt;em&gt;nothing&lt;/em&gt; about where we should put the jar, we let Gradle pick a reasonable place for us.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then what are the inputs of the &lt;code&gt;jar&lt;/code&gt; task itself? Well, it&amp;#8217;s regular inputs &lt;strong&gt;plus&lt;/strong&gt; our jar. It&amp;#8217;s easier to reason about, and as bonus, it&amp;#8217;s even shorter to write!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So let&amp;#8217;s rewrite the code above to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;task docFilesJar(type: Jar, description: &apos;Package up files used for generating documentation.&apos;) {
    archiveVersion = null
    archiveFileName = &quot;grails-doc-files.jar&quot;
    from &quot;src/main/template&quot;
}

jar {
    from docFilesJar
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can you spot the difference? We got rid of the &lt;code&gt;copy&lt;/code&gt; in the &lt;code&gt;docFilesJar&lt;/code&gt; task, we don&amp;#8217;t want to do this. What we want, instead, is to say &quot;when you build the jar, also pick this &lt;code&gt;docsFileJar&lt;/code&gt;. And that&amp;#8217;s what we&amp;#8217;re doing by telling &lt;code&gt;from docsFileJar&lt;/code&gt;. Gradle is smart enough to know that when it will need to execute the &lt;code&gt;jar&lt;/code&gt; task, first, it will need to build the &lt;code&gt;docsFilesJar&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are several advantages to this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the dependency becomes &lt;em&gt;implicit&lt;/em&gt;: if we don&amp;#8217;t want to include the jar anymore, we just have to remove it from the specification of the inputs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it doesn&amp;#8217;t pollute the outputs of other tasks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you can execute the &lt;code&gt;docsFileJar&lt;/code&gt; independently of &lt;code&gt;jar&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All in all, it&amp;#8217;s about isolating things from each other and reducing the risks of breaking a build accidentally!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_all_things_lazy&quot;&gt;All things lazy!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The modified code isn&amp;#8217;t 2021 compliant. The code above works, but it has one drawback: the &lt;code&gt;docFilesJar&lt;/code&gt; and &lt;code&gt;jar&lt;/code&gt; tasks are going to be configured (instantitated) even if we call something that doesn&amp;#8217;t need it. For example, imagine that you call &lt;code&gt;gradle compileJava&lt;/code&gt;: there&amp;#8217;s no reason to configure the &lt;code&gt;jar&lt;/code&gt; tasks there because we won&amp;#8217;t execute them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For this purpose, to make builds faster, Gradle provides a &lt;em&gt;lazy API&lt;/em&gt; instead:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.register(&apos;docFilesJar&apos;, Jar) {
    description = &apos;Package up files used for generating documentation.&apos;
    archiveVersion = null
    archiveFileName = &quot;grails-doc-files.jar&quot;
    from &quot;src/main/template&quot;
}

tasks.named(&apos;jar&apos;, Jar) {
    from docFilesJar
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a conclusion:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;avoid using explicit &lt;code&gt;dependsOn&lt;/code&gt; &lt;em&gt;as much as you can&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tend to say that the only reasonable use case for &lt;code&gt;dependsOn&lt;/code&gt; is for lifecycle tasks (lifecycle tasks are tasks which goal is only there to &quot;organize the build&quot;, for example &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;assemble&lt;/code&gt;, &lt;code&gt;check&lt;/code&gt;: they don&amp;#8217;t do anything by themselves, they just bind a number of dependents together)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;if you find use cases which are not lifecycle tasks and cannot be expressed by &lt;em&gt;implicit task dependencies&lt;/em&gt; (e.g declaring inputs instead of &lt;code&gt;dependsOn&lt;/code&gt;), then report it to the Gradle team&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Frequently asked questions about version catalogs</title>
      <link>https://melix.github.io/blog//2021/03/version-catalogs-faq.html</link>
      <pubDate>Sun, 11 Apr 2021 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2021/03/version-catalogs-faq.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This post is a follow up to my &lt;a href=&quot;/blog/2021/03/version-catalogs.html&quot;&gt;version catalogs intro blog post&lt;/a&gt; and answers some frequently asked questions.
Ideally, this should be part of the Gradle docs itself but we don&amp;#8217;t have a good place for this kind of docs yet (I&amp;#8217;m working on it!), so in the meantime, here you go!
This blog post will be updated as I&amp;#8217;m seeing more questions.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&quot;toc&quot; class=&quot;toc&quot;&gt;
&lt;div id=&quot;toctitle&quot; class=&quot;title&quot;&gt;Table of Contents&lt;/div&gt;
&lt;ul class=&quot;sectlevel1&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_version_catalogs_faq&quot;&gt;Version catalogs FAQ&lt;/a&gt;
&lt;ul class=&quot;sectlevel2&quot;&gt;
&lt;li&gt;&lt;a href=&quot;#_can_i_use_a_version_catalog_to_declare_plugin_versions&quot;&gt;Can I use a version catalog to declare plugin versions?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_can_i_use_the_version_catalog_in_buildsrc&quot;&gt;Can I use the version catalog in buildSrc?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_but_how_can_i_use_the_catalog_in_plugins_defined_in_buildsrc&quot;&gt;But how can I use the catalog in &lt;em&gt;plugins&lt;/em&gt; defined in &lt;code&gt;buildSrc&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_can_i_use_version_catalogs_in_production_code&quot;&gt;Can I use version catalogs in production code?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_should_i_use_a_platform_or_a_catalog&quot;&gt;Should I use a platform or a catalog?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_why_did_you_choose_toml_and_not_yaml&quot;&gt;Why did you choose TOML and not YAML?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_my_ide_is_red_everywhere_missing_dependency_class_error&quot;&gt;My IDE is red everywhere, MISSING_DEPENDENCY_CLASS error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_why_cant_i_have_nested_aliases_with_the_same_prefix&quot;&gt;Why can&amp;#8217;t I have nested aliases with the same prefix?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_why_cant_i_use_an_alias_with_dots_directly&quot;&gt;Why can&amp;#8217;t I use an alias with dots directly?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_should_i_use_commons_lang3_as_an_alias_or_commonslang3&quot;&gt;Should I use &lt;code&gt;commons-lang3&lt;/code&gt; as an alias or &lt;code&gt;commonsLang3&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_should_i_use_the_settings_api_or_the_toml_file&quot;&gt;Should I use the settings API or the TOML file?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_why_cant_i_use_excludes_or_classifiers&quot;&gt;Why can&amp;#8217;t I use excludes or classifiers?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_how_do_i_tell_gradle_to_use_a_specific_artifact&quot;&gt;How do I tell Gradle to use a specific &lt;em&gt;artifact&lt;/em&gt;?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#_where_should_i_report_bugs_or_feature_requests&quot;&gt;Where should I report bugs or feature requests?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_version_catalogs_faq&quot;&gt;Version catalogs FAQ&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_can_i_use_a_version_catalog_to_declare_plugin_versions&quot;&gt;Can I use a version catalog to declare plugin versions?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;No.The initial implementation of the version catalogs had, in TOML files, a dedicated section for plugins:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[plugins]
id.of.my.awesome.plugin=&quot;1.2.3&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, after community feedback and for &lt;a href=&quot;https://github.com/gradle/gradle/issues/16078&quot;&gt;consistency reasons&lt;/a&gt;, we removed this feature from the initial release.
This means that &lt;em&gt;currently&lt;/em&gt;, you have to use the &lt;code&gt;pluginManagement&lt;/code&gt; section of the settings file to deal with your plugin versions, and this cannot use, in particular, the TOML file to declare plugin versions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;pluginManagement {
    plugins {
        id(&quot;me.champeau.jmh&quot;) version(&quot;0.6.3&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It may look surprising that you can&amp;#8217;t use &lt;code&gt;version(libs.plugins.jmh)&lt;/code&gt; for example in the &lt;code&gt;pluginManagement&lt;/code&gt; block, but it&amp;#8217;s a chicken and egg problem: the &lt;code&gt;pluginManagement&lt;/code&gt; block has to be evaluated &lt;em&gt;before&lt;/em&gt; the catalogs are defined, because &lt;em&gt;settings plugins&lt;/em&gt; may contribute more catalogs or enhance the existing catalogs. Therefore, the &lt;code&gt;libs&lt;/code&gt; extension doesn&amp;#8217;t exist when this block is evaluated.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The limitation of not being able to deal with plugin versions in catalogs will be lifted in one way or another in the future.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_can_i_use_the_version_catalog_in_buildsrc&quot;&gt;Can I use the version catalog in buildSrc?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes you can. Not only in &lt;code&gt;buildSrc&lt;/code&gt;, but basically in any included build too. You have several options, but the easiest is to include the TOML catalog in your &lt;code&gt;buildSrc/settings.gradle(.kts)&lt;/code&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;buildSrc/settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencyResolutionManagement {
    versionCatalogs {
        lib {
            from(files(&quot;../gradle/libs.versions.toml&quot;))
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_but_how_can_i_use_the_catalog_in_plugins_defined_in_buildsrc&quot;&gt;But how can I use the catalog in &lt;em&gt;plugins&lt;/em&gt; defined in &lt;code&gt;buildSrc&lt;/code&gt;?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The solution above lets you use the catalogs in the build scripts of &lt;code&gt;buildSrc&lt;/code&gt; itself, but what if you want to use the catalog(s) in the plugins that &lt;code&gt;buildSrc&lt;/code&gt; defines, or precompiled script plugins?
Long story short, currently, you can do it using a &lt;em&gt;type unsafe&lt;/em&gt; API only.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First you need to access the version catalogs extension to your plugin/build script, for example in Groovy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def catalogs = project.extensions.getByType(VersionCatalogsExtension)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or in Kotlin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;val catalogs = extensions.getByType&amp;lt;VersionCatalogsExtension&amp;gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then you can access the version catalogs in your script, for example writing:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;pluginManager.withPlugin(&quot;java&quot;) {
    val libs = catalogs.named(&quot;libs&quot;)
    dependencies.addProvider(&quot;implementation&quot;, libs.findDependency(&quot;lib&quot;).get())
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that this API doesn&amp;#8217;t provide any static accessor but is nevertheless safe, using the &lt;code&gt;Optional&lt;/code&gt; API.
There&amp;#8217;s a reason why you cannot access type-safe accessors in plugins/precompiled script plugins, you will find more details on this &lt;a href=&quot;https://github.com/gradle/gradle/issues/15383&quot;&gt;issue&lt;/a&gt;.
In a nutshell, that&amp;#8217;s because &lt;code&gt;buildSrc&lt;/code&gt; plugins (precompiled or not) are &lt;em&gt;plugins&lt;/em&gt; which can be applied to any kind of project and we don&amp;#8217;t know what the &lt;em&gt;target project catalogs&lt;/em&gt; will be: there&amp;#8217;s no inherent reason why they would be the same.
In the future we will probably provide a way to explain that, at your own risk, expect the target catalog model to be the same.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_can_i_use_version_catalogs_in_production_code&quot;&gt;Can I use version catalogs in production code?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;No, you can&amp;#8217;t. Version catalogs are only accessible to build scripts/plugins, not your production code.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_should_i_use_a_platform_or_a_catalog&quot;&gt;Should I use a platform or a catalog?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You should probably use both, look at our &lt;a href=&quot;https://docs.gradle.org/7.0/userguide/platforms.html#sub:platforms-vs-catalog&quot;&gt;docs&lt;/a&gt; for a complete explanation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_did_you_choose_toml_and_not_yaml&quot;&gt;Why did you choose TOML and not YAML?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or XML (or pick your favorite format). The rationale is described in the &lt;a href=&quot;https://github.com/gradle/gradle/files/5646826/2020-12-05-Central.declaration.of.dependencies.Shared.externally.pdf&quot;&gt;design document&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_my_ide_is_red_everywhere_missing_dependency_class_error&quot;&gt;My IDE is red everywhere, MISSING_DEPENDENCY_CLASS error&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are seeing this error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/missing-dependency.png&quot; alt=&quot;missing dependency&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;upgrade to the latest IntelliJ IDEA 2021.1, which fixes this problem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_cant_i_have_nested_aliases_with_the_same_prefix&quot;&gt;Why can&amp;#8217;t I have nested aliases with the same prefix?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine that you want to have 2 aliases, say &lt;code&gt;junit&lt;/code&gt; and &lt;code&gt;junit-jupiter&lt;/code&gt; and that both represent distinct dependencies: Gradle won&amp;#8217;t let you do this and you will have to rename your aliases to, say &lt;code&gt;junit-core&lt;/code&gt; and &lt;code&gt;junit-jupiter&lt;/code&gt;.
That&amp;#8217;s because Gradle will map those aliases to &lt;em&gt;accessors&lt;/em&gt;, that is to say &lt;code&gt;libs.getJunit()&lt;/code&gt; and &lt;code&gt;libs.getJUnit().getJupiter()&lt;/code&gt;.
The problem is that you can&amp;#8217;t have an accessor which is both a &lt;em&gt;leaf&lt;/em&gt; (represents a dependency notation) and a &lt;em&gt;node&lt;/em&gt; (that is to say an intermediate node to access a real dependency).
The reason we can&amp;#8217;t do this is that we&amp;#8217;re using lazy accessors of type &lt;code&gt;Provider&amp;lt;MinimalExternalDependency&amp;gt;&lt;/code&gt; for leaves and that type &lt;em&gt;cannot&lt;/em&gt; be extended to provide accessors for &quot;children&quot; dependencies.
In other words, the type which represents a &lt;em&gt;node with children&lt;/em&gt; provides accessors which return &lt;code&gt;Provider&amp;lt;&amp;#8230;&amp;#8203;&amp;gt;&lt;/code&gt; for dependencies, but a provider itself cannot have children.
A potential workaround for this would be to support, in the future, an explicit call to say &quot;I&amp;#8217;m stopping here, that&amp;#8217;s the dependency I need&quot;, for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;dependencies {
    testImplementation(libs.junit.get())
    // or
    testImplemementation(libs.junit.peek()) // because `get()` might be confusing as it would return a `Provider` on which you can call `get()` itself
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For now the team has decided to restrict what you can do by preventing having aliases which have &quot;name clashes&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_cant_i_use_an_alias_with_dots_directly&quot;&gt;Why can&amp;#8217;t I use an alias with dots directly?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will have noticed that if you declare an alias like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[libraries]
junit-jupiter = &quot;...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then Gradle will generate the following accessor: &lt;code&gt;libs.junit.jupiter&lt;/code&gt; (basically the dashes are transformed to dots).
The question is, why can&amp;#8217;t we just write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[libraries]
junit.jupiter = &quot;...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And the reason is: tooling support. The previous declaration is actually equivalent to writing:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[libraries]
   [junit]
   jupiter = &quot;...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;but technically, it&amp;#8217;s undecidable where the &quot;nesting hierarchy&quot; stops, which would prevent tools from providing good completion (for example, where you can use &lt;code&gt;{ module = &quot;&amp;#8230;&amp;#8203;&quot;}&lt;/code&gt;.
It also makes it harder for tooling to automatically patch the file since they wouldn&amp;#8217;t know where to look for.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, we&amp;#8217;ve decided to keep the format simple and implement this mapping strategy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_should_i_use_commons_lang3_as_an_alias_or_commonslang3&quot;&gt;Should I use &lt;code&gt;commons-lang3&lt;/code&gt; as an alias or &lt;code&gt;commonsLang3&lt;/code&gt;?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Problably neither one nor the other :) By choosing &lt;code&gt;commons-lang3&lt;/code&gt;, you&amp;#8217;re implicitly creating a &lt;em&gt;group of dependencies&lt;/em&gt; called &lt;code&gt;commons&lt;/code&gt;, which will include a number of dependencies, including &lt;code&gt;lang3&lt;/code&gt;.
The question then is, does that &lt;code&gt;commons&lt;/code&gt; group make sense? It&amp;#8217;s rather abstract, no? Does it actually say it&amp;#8217;s &quot;Apache Commons&quot;?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A better solution would therefore be to use &lt;code&gt;commonsLang3&lt;/code&gt; as the alias, but then you&amp;#8217;d realize that you have chosen a version in the alias name, so why not &lt;code&gt;commonsLang&lt;/code&gt; directly?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[libraries]
commonsLang = { module=&quot;org.apache.commons:commons-lang3:3.3.1&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that the dashes should be limited to grouping of dependencies, so that they are organized in &quot;folders&quot;.
This can make it practical when you have lots of dependencies, but it also makes them less discoverable by completion, since you&amp;#8217;d have to know in which subtree to look at.
Proper guidance on what to use will be discussed later, based on your feedback and practices.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_should_i_use_the_settings_api_or_the_toml_file&quot;&gt;Should I use the settings API or the TOML file?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle comes with both a settings API to declare the catalog, or a convenience TOML file.
I would personally say that most people should only care about the TOML file as it covers 80% of use cases.
The settings API is great as soon as you want to implement &lt;em&gt;settings plugins&lt;/em&gt; or, for example, if you want to use your own, existing format to declare a catalog, instead of using the TOML format.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_cant_i_use_excludes_or_classifiers&quot;&gt;Why can&amp;#8217;t I use excludes or classifiers?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By design, version catalogs talk about &lt;em&gt;dependency coordinates&lt;/em&gt; only.
The choice of applying excludes is on the consumer side: for example, for a specific project, you might need to exclude a transitive dependency because you don&amp;#8217;t use the code path which exercises this dependency, but this might not be the case for all places.
Similarly, a classifier falls into the category of &lt;em&gt;variant selectors&lt;/em&gt; (see &lt;a href=&quot;https://docs.gradle.org/current/userguide/variant_model.html&quot;&gt;the variant model&lt;/a&gt;): for the same dependency coordinates, one might want classifier X, another classifier Y, and it&amp;#8217;s not necessarily allowed to have both in the same graph.
Therefore, classifiers need to be declared on the &lt;em&gt;dependency declaration site&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;dependencies {
   implementation(variantOf(libs.myLib) { classifier(&apos;test-fixtures&apos;) })
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The rationale being this limitation is that the use of classifiers is an artifact of the poor &lt;code&gt;pom.xml&lt;/code&gt; modeling, which doesn&amp;#8217;t assign semantics to classifiers (we don&amp;#8217;t know what they represent), contrary to Gradle Module Metadata.
Therefore, a consumer should only care about the dependency coordinates, and the right variant (e.g classifier) should be selected automatically by the dependency resolution engine.
We want to encourage this model, rather than supporting &lt;em&gt;adhoc&lt;/em&gt; classifiers which will eventually require more work for all consumers.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_how_do_i_tell_gradle_to_use_a_specific_artifact&quot;&gt;How do I tell Gradle to use a specific &lt;em&gt;artifact&lt;/em&gt;?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly to classifiers or excludes, &lt;em&gt;artifact selectors&lt;/em&gt; belong to the dependency declaration site. You need to write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
    implementation(libs.myLib) {
        artifact {
            name = &apos;my-lib&apos; // note that ideally this will go away, see https://github.com/gradle/gradle/issues/16768
            type = &apos;aar&apos;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_where_should_i_report_bugs_or_feature_requests&quot;&gt;Where should I report bugs or feature requests?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As usual, on our &lt;a href=&quot;https://github.com/gradle/gradle/issues&quot;&gt;issue tracker&lt;/a&gt;. There&amp;#8217;s also the dedicated &lt;a href=&quot;https://github.com/gradle/gradle/issues/15352&quot;&gt;epic&lt;/a&gt; where you will find the initial specification linked, which explains a lot of the design process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Simplified version management with Gradle 7</title>
      <link>https://melix.github.io/blog//2021/03/version-catalogs.html</link>
      <pubDate>Wed, 24 Mar 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/03/version-catalogs.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle 7 introduces the concept of &lt;a href=&quot;https://docs.gradle.org/7.0-rc-1/userguide/platforms.html&quot;&gt;version catalogs&lt;/a&gt;, which I&amp;#8217;ve been working on for several months already. Long story short, I&amp;#8217;m extremely excited by this new feature which should make dependency management easier with Gradle. Let&amp;#8217;s get started!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Please also read my &lt;a href=&quot;/blog/2021/03/version-catalogs-faq.html&quot;&gt;Version catalogs FAQ&lt;/a&gt; follow up post if you have more questions!&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_sharing_dependencies_between_projects&quot;&gt;Sharing dependencies between projects&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the most frequent questions raised by Gradle users is how to properly share dependency versions between projects.
For example, let&amp;#8217;s imagine that you have a multi-project build with this layout:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;root
 |---- client
 |---- server&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because they live in the same &quot;multi-project&quot;, it is expected that both &lt;code&gt;client&lt;/code&gt; and &lt;code&gt;server&lt;/code&gt; would require the same dependencies.
For example, both of them would need Guava as an implementation detail and JUnit 5 for testing:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
    implementation(&quot;com.google.guava:guava:30.0-jre&quot;)
    testImplementation(&quot;org.junit.jupiter:junit-jupiter-api:5.7.1&quot;)
    testRuntimeOnly(&quot;org.junit.jupiter:junit-jupiter-engine&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Without any sharing mechanism, both projects would replicate the dependency declarations, which is subject to a number of drawbacks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;upgrading a library requires updating all build files which use it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you have to remember about the dependency coordinates (group, artifact, version) of all dependencies&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you might accidentally use different versions in different projects&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;some dependencies are always used together but you have to duplicate entries in build files&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_existing_patterns&quot;&gt;Existing patterns&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For these reasons, users have invented over the years different patterns for dealing with dependency versions over time.
For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Versions in properties files:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;gradle.properties&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;guavaVersion=30.0-jre&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then in a build file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;dependencies {
    implementation(&quot;com.google.guava:guava:${guavaVersion}&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Or versions in &quot;extra properties&quot; in the root project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;extra properties&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;ext {
   guavaVersion = &apos;30.0-jre&apos;
}

// ...

dependencies {
    implementation(&quot;com.google.guava:guava:${guavaVersion}&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sometimes you even find full coordinates in &lt;code&gt;dependencies.gradle&lt;/code&gt; files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And since the rise of the Kotlin DSL, another pattern became extremely popular in the Android world: declaring libraries in &lt;code&gt;buildSrc&lt;/code&gt; then using type-safe accessors to declare dependencies in build scripts:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;buildSrc/src/main/kotlin/Libs.kt&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;object Libs {
   val guava = &quot;com.google.guava:guava:30.0-jre&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and in a build script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;dependencies {
    implementation(Libs.guava)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This last example is interesting because it goes into the direction of having more type-safety, more compile-time errors (as opposed to runtime errors).
But it has a major drawback: any change to any dependency will trigger recompilation of build scripts and invalidate the build script classpath, causing up-to-date checkness to fail and in the end, rebuilding a lot more than what you should do for a single version change.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introducing_version_catalogs&quot;&gt;Introducing version catalogs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A version catalog is basically a replacement for all the previous patterns, supported by Gradle, without the drawbacks of the previous approaches.
To add support for version catalogs, you need to enable the experimental feature in your settings file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;enableFeaturePreview(&quot;VERSION_CATALOGS&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In its simplest form, a catalog is a file found in a conventional location and uses the &lt;a href=&quot;https://toml.io/en/&quot;&gt;TOML&lt;/a&gt; configuration format:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;gradle/libs.versions.toml&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[libraries]
guava = &quot;com.google.guava:guava:30.0-jre&quot;
junit-jupiter = &quot;org.junit.jupiter:junit-jupiter-api:5.7.1&quot;
junit-engine = { module=&quot;org.junit.jupiter:junit-jupiter-engine&quot; }

[bundles]
testDependencies = [&quot;junit-jupiter&quot;, &quot;junit-engine&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This declares the &lt;em&gt;dependency coordinates&lt;/em&gt; which will be used in build scripts.
You still have to declare your dependencies, but this now can be done using a &lt;em&gt;typesafe&lt;/em&gt; API:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
    implementation(libs.guava)
    testImplementation(libs.testDependencies)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The benefit of type-safe APIs is immediately visible in the IDE:&lt;/p&gt;
&lt;/div&gt;
&lt;video controls autoplay height=&quot;450&quot;&gt;
    &lt;source src=&quot;/blog/video/ide-completion.webm&quot;
            type=&quot;video/webm&quot;&gt;
&lt;/video&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the catalog file above, we inlined dependency versions directly in the coordinates.
However, it&amp;#8217;s possible to externalize them so that you can share a dependency version between dependencies.
For example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;gradle/libs.versions.toml&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;[versions]
groovy = &quot;2.5.14&quot;
guava = &quot;30.0-jre&quot;
jupiter = &quot;5.7.1&quot;

[libraries]
guava = { module=&quot;com.google.guava:guava&quot;, version.ref=&quot;guava&quot; }
junit-jupiter = { module=&quot;org.junit.jupiter:junit-jupiter-api&quot;, version.ref=&quot;jupiter&quot; }
junit-engine = { module=&quot;org.junit.jupiter:junit-jupiter-engine&quot; }

groovy-core = { module=&quot;org.codehaus.groovy:groovy&quot;, version.ref=&quot;groovy&quot; }
groovy-json = { module=&quot;org.codehaus.groovy:groovy-json&quot;, version.ref=&quot;groovy&quot; }

[bundles]
testDependencies = [&quot;junit-jupiter&quot;, &quot;junit-engine&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This new feature makes it trivial to update a dependency version: you have a single place where to look at.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This comes with other benenefits like the fact that updating the GAV coordinates (group, artifact or version) of a dependency doesn&amp;#8217;t trigger recompilation of build scripts.
The TOML format also provides us with the ability to declare &lt;a href=&quot;https://docs.gradle.org/7.0-rc-1/userguide/rich_versions.html&quot;&gt;rich versions&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_under_the_hood&quot;&gt;Under the hood&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Under the hood, Gradle provides an API to declare catalogs. This API is found on the &lt;code&gt;Settings&lt;/code&gt;, which means that plugin authors can contribute catalogs, for example via convention plugins applied to the &lt;code&gt;settings.gradle(.kts)&lt;/code&gt; file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This API is more verbose than when you use the TOML file, but is designed for type-safety. The equivalent of the catalog above would be this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencyResolutionManagement {
   versionCatalogs {
      libs {
           alias(&quot;guava&quot;).to(&quot;com.google.guava&quot;, &quot;guava&quot;).versionRef(&quot;guava&quot;)
           alias(&quot;junit-jupiter&quot;).to(&quot;org.junit.jupiter&quot;, &quot;junit-jupiter-api&quot;).versionRef(&quot;jupiter&quot;)
           alias(&quot;junit-engine&quot;).to(&quot;org.junit.jupiter&quot;, &quot;junit-jupiter-engine&quot;).withoutVersion()
           alias(&quot;groovy-core&quot;).to(&quot;org.codehaus.groovy&quot;, &quot;groovy&quot;).versionRef(&quot;groovy&quot;)
           alias(&quot;groovy-json&quot;).to(&quot;org.codehaus.groovy&quot;, &quot;groovy-json&quot;).versionRef=&quot;groovy&quot;)

           version(&quot;groovy&quot;, &quot;2.5.14&quot;)
           version(&quot;guava&quot;, &quot;30.0-jre&quot;)
           version(&quot;jupiter&quot;, &quot;5.7.1&quot;)
      }
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This API actually must be used if you are &lt;em&gt;consuming an external catalog&lt;/em&gt;.
That&amp;#8217;s one of the big selling points of this feature: it allows teams (or framework authors) to &lt;em&gt;publish catalogs&lt;/em&gt;, so that users can get recommendations.
For example, let&amp;#8217;s imagine that the Spring Boot team &lt;a href=&quot;https://docs.gradle.org/7.0-rc-1/userguide/platforms.html#sec:version-catalog-plugin&quot;&gt;publishes a catalog of recommendations&lt;/a&gt; (they do something similar today with a BOM, but BOMs will have an impact on your transitive dependencies that you might not want).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Consuming this catalog it in a Gradle build would look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;settings.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencyResolutionManagement {
   versionCatalogs {
       spring {
           from(&quot;org.springframework:spring-catalog:1.0&apos;)
       }
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This would make a catalog available under the &lt;code&gt;spring&lt;/code&gt; namespace in your build scripts.
Therefore, you&amp;#8217;d be able to use whatever version of SLF4J the Spring team recommends by declaring this dependency:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
    implementation(spring.slf4j)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Such a catalog would be published on a regular Maven repository, as a TOML file.
Thanks to Gradle&amp;#8217;s advanced dependency resolution engine, it&amp;#8217;s totally transparent to the user that the actual dependency is a &lt;em&gt;catalog&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_what_version_catalogs_are_not&quot;&gt;What version catalogs are not&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, it becomes important to state what version catalogs are &lt;strong&gt;not&lt;/strong&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;they &lt;strong&gt;are not&lt;/strong&gt; the &quot;single source of truth&quot; for your dependencies: it&amp;#8217;s not because you have a catalog that you can&amp;#8217;t directly declare dependencies using the &quot;old&quot; notation in build scripts. Nor does it prevent plugins from adding dependencies. Long story short: the presence of a catalog makes discoverability and maintenance easier, but it doesn&amp;#8217;t remove any of the flexibility that Gradle offers. We&amp;#8217;re thinking about ways to &lt;em&gt;enforce&lt;/em&gt; that all direct dependencies are declared via a catalog in the future.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the version declared in a catalog &lt;strong&gt;is not&lt;/strong&gt; necessarily the one which is going to be resolved: a catalog only talks about direct dependencies (not transitives) and the version that you use is the one used as an &lt;em&gt;input&lt;/em&gt; to dependency resolution. With transitive dependencies, it&amp;#8217;s typically possible that a version gets upgraded, for example.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;while it makes it possible for third-party tooling to &quot;update automatically&quot; versions, this wasn&amp;#8217;t a goal of this work. If you relate to the previous point, it all makes sense: as long as you rely on the &lt;em&gt;input&lt;/em&gt; (what is written) to assume what is going to be resolved, you&amp;#8217;re only &lt;em&gt;wishing&lt;/em&gt; that it is what is going to be resolved. It may be enough for some cases, though. Please refer to my &lt;a href=&quot;https://melix.github.io/blog/2020/10/about-dependabot.html&quot;&gt;blog post about Dependabot&lt;/a&gt; for more insights on this topic. Again, future work we have in mind is adding some linting to make sure that the first level dependencies you declare match whatever you resolved, because in general, having a difference there is a sign that something is wrong in the setup. I&amp;#8217;m going to repeat myself, but &lt;strong&gt;don&amp;#8217;t assume that the version you see in a config file is the one you will get&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Please take a look at the &lt;a href=&quot;https://docs.gradle.org/7.0-rc-1/userguide/platforms.html#sub:central-declaration-of-dependencies&quot;&gt;documentation&lt;/a&gt; for further details, and give us your feedback!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Using Java 16 with Gradle</title>
      <link>https://melix.github.io/blog//2021/03/gradle-java16.html</link>
      <pubDate>Wed, 17 Mar 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/03/gradle-java16.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/java/status/1371842658256228356&quot;&gt;Java 16 is out&lt;/a&gt; and I&amp;#8217;m seeing a number of folks trying to figure out how to use Java 16 with Gradle.
Often they would try to run Gradle with JDK 16 and see it fail.
There&amp;#8217;s a &lt;a href=&quot;https://github.com/gradle/gradle/issues/13481&quot;&gt;ticket about Java 16 support in Gradle&lt;/a&gt; but in most cases you can already work with JDK 16 without waiting for official support.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_happy_path&quot;&gt;The happy path&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle 7, which is due soon, will provide official support for Java 16.
If you have an existing build that you want to try on Java 16, you can update the wrapper to use the latest Gradle 7.0 milestone release:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;gradle/wrapper/gradle-wrapper.properties&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-milestone-3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are lucky this is all you need to do.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, Gradle 7 is a major release, and as such it brings a number of changes which &lt;em&gt;may&lt;/em&gt; break your build (deprecated methods being removed, or, in particular for the Java 16 support, upgrading to Groovy 3 internally).
It may be a bit involved to migrate to Gradle 7 just to try Java 16.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_decouple_the_java_version_used_for_gradle_itself_from_the_version_you_need&quot;&gt;Decouple the Java version used for Gradle itself from the version you need!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s actually better to &lt;em&gt;decouple the version of Java required to run Gradle&lt;/em&gt; from the &lt;em&gt;version of Java your application requires&lt;/em&gt;.
In general, it&amp;#8217;s actually considered the &lt;strong&gt;best practice&lt;/strong&gt; to use whatever version of the JDK Gradle officially supports to run Gradle itself, and configure the build to &lt;strong&gt;use a different JDK&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_java_toolchains&quot;&gt;Configuring Java toolchains&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Gradle terminology, this is called activating &lt;a href=&quot;https://docs.gradle.org/6.8.3/userguide/toolchains.html&quot;&gt;Java Toolchains&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s get started with a sample project running on latest stable Gradle, which is 6.8.3.
Make sure that you have Gradle 6.8.3 on your PATH to get started.
I&amp;#8217;m personally recommending to use &lt;a href=&quot;https://sdkman.io/&quot;&gt;sdkman!&lt;/a&gt; to install Gradle:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ sdk install gradle 6.8.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the same time, we want to make sure we run Gradle with a supported version, which is anything between Java 8 and 15:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ java -version
java -version
openjdk version &quot;11.0.9.1&quot; 2020-11-04
OpenJDK Runtime Environment 18.9 (build 11.0.9.1+1)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.9.1+1, mixed mode)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If it outputs something else than 8 to 15, please make sure to update your PATH to point to such a JDK.
Again you can do this with sdkman!:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ sdk install java 11.0.9.open&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_demo_application&quot;&gt;Demo application&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, let&amp;#8217;s create a sample Gradle project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ mkdir demo-app
$ cd demo-app
$ gradle init&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then select:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit 4) [1..4] 4

Project name (default: demo-app):
Source package (default: demo.app):&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and confirm the default name and packages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then let&amp;#8217;s run our app:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;$ ./gradlew run

&amp;gt; Task :app:run
Hello World!

BUILD SUCCESSFUL in 4s
2 actionable tasks: 2 executed&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_migrating_the_application_to_java_16&quot;&gt;Migrating the application to Java 16&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All good! Now let&amp;#8217;s configure Gradle to use Java 16 to build and run our app instead.
Let&amp;#8217;s open the build script, found under &lt;code&gt;app&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;app/build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id &apos;application&apos;
}

// Add this under the `plugins` section:
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(16)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;java.toolchain&lt;/code&gt; block lets us configure the &lt;em&gt;toolchain&lt;/em&gt; that Gradle is going to use to build and run your application.
We&amp;#8217;re setting 16, which means that we&amp;#8217;re going to compile the main and test sources as well as execute the with a Java 16 JDK.
Gradle will automatically try to find if you have a Java 16 installation in a conventional location.
If it cannot find one you will see something like this happening:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Provisioning toolchain adoptopenjdk-16-x64-linux.tar.gz &amp;gt; adoptopenjdk-16-x64-linux.tar.gz &amp;gt; 66 MiB/195.8 MiB&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which means that Gradle is downloading the JDK for you!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s check:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;./gradlew run&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Dang!&lt;/strong&gt; The &lt;a href=&quot;https://scans.gradle.com/s/gogpwzdj5zf6q/console-log?anchor=14&quot;&gt;build fails!&lt;/a&gt;.
To some extent, it&amp;#8217;s good news, it means that Gradle is really using Java 16, but why is it failing?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_disabling_incremental_compilation&quot;&gt;Disabling incremental compilation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, you&amp;#8217;re facing one of the bugs we fixed in 7, which is that our &lt;em&gt;incremental compiler&lt;/em&gt; isn&amp;#8217;t compatible with Java 16 because we&amp;#8217;re using classes which have been made &quot;hidden&quot; by the module system in Java 16.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There&amp;#8217;s an easy fix: let&amp;#8217;s disable incremental compilation!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again, let&amp;#8217;s open our &lt;code&gt;app/build.gradle&lt;/code&gt; file and add this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;tasks.withType(JavaCompile).configureEach {
	// disable incremental compilation
    options.incremental = false
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And let&amp;#8217;s run the build again:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;bash&quot;&gt;./gradlew run&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yay! This time the &lt;a href=&quot;https://scans.gradle.com/s/czapxbvfqxt72/console-log?anchor=7&quot;&gt;build passed!&lt;/a&gt;
Congrats, you have your first Java 16 app running!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alternatively to disabling incremental compilation, you might just want to let Gradle access the JDK internals.
This solution is better for performance, even if a bit &quot;hackish&quot;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;tasks.withType(JavaCompile).configureEach {
    options.forkOptions.jvmArgs.addAll( [&apos;--add-opens&apos;, &apos;jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED&apos;] )
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In case you want to use one of the experimental features that Java 16 provides, the setup I&amp;#8217;ve described in a &lt;a href=&quot;https://melix.github.io/blog/2020/06/java-feature-previews-gradle.html&quot;&gt;previous post about Java Feature Previews&lt;/a&gt; still hold and is a good follow-up to this post!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle + WebAssembly</title>
      <link>https://melix.github.io/blog//2021/02/gradle-webassembly.html</link>
      <pubDate>Sun, 21 Feb 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/02/gradle-webassembly.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A couple weeks ago, I listened to an &lt;a href=&quot;https://medium.com/electro-monkeys/64-la-face-cach%C3%A9e-de-webassembly-avec-geoffroy-couprie-et-ivan-enderline-bd20e5482893&quot;&gt;interview (in French)&lt;/a&gt; of &lt;a href=&quot;https://twitter.com/gcouprie&quot;&gt;Geoffroy Couprie&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/mnt_io&quot;&gt;Ivan Enderlin&lt;/a&gt; who gave a very nice overview of what WebAssembly is and what it&amp;#8217;s good for.
To be honest it wasn&amp;#8217;t clear to me what the advantages of WebAssembly were, compared to a good old JVM: all in all, both are virtual machines, and both promise the same thing, that is to say write once run everywhere.
Also, in my mind, WebAssembly was some kind of restricted version of JavaScript like &lt;a href=&quot;https://en.wikipedia.org/wiki/Asm.js&quot;&gt;asm.js&lt;/a&gt;.
I was wrong: it&amp;#8217;s more than that.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_why_webassembly&quot;&gt;Why WebAssembly?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the aspects which were discussed during this interview was basically sandboxing: with WebAssembly, it&amp;#8217;s the responsibility of the embedder to give access, for example, to I/O to the wasm program. In practice, it means that wasm binaries are by default very restricted.
In fact, by design, they are restricted to pure computations, which makes them very suitable for isolation of work.
Extensions from embedders are responsible for giving access to the host resources (for example the GPU, or the file system).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another promise of WebAssembly is running at close-to-native speeds.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, a crazy idea came to me: what if I could use a wasm binary as a task implemention in Gradle?
This, for example, would let us use whatever language compiling to WASM as an implementation language for Gradle tasks. &lt;em&gt;mmmmmmm&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The result of this experience is available at &lt;a href=&quot;https://github.com/melix/gradle-wasm-plugin&quot;&gt;this repository&lt;/a&gt;.
The results are quite promising.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_isolating_task_inputs_from_the_task_execution&quot;&gt;Isolating task inputs from the task execution&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, a Gradle task can be seen as a function which takes a number of inputs and returns a value.
Cacheability is derived from the &quot;pureness&quot; of the function: for the same inputs, the output should be the same.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This makes it very suitable to the WebAssembly model where functions are exported to an embedder.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In reality, it&amp;#8217;s more complicated: Gradle tasks most likely use files as inputs, and also produce files.
This means that the WebAssembly runtime would need to provide I/O access for this to be really useful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After some support from &lt;a href=&quot;https://twitter.com/mnt_io&quot;&gt;Ivan Enderlin&lt;/a&gt;, I quickly figured out that it would be difficult to make file access work, so I simplified the problem.
In the prototype, my WASM tasks are not able to produce a file output and are limited to simply display the execution result on the console.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For tasks which actually have files as inputs, I&amp;#8217;m reading the file contents from Java code into byte arrays which are &quot;propagated&quot; to the WASM runtime memory.
This means, effectively, that the WASM functions I played with don&amp;#8217;t have any kind of access to the file system and remain pure functions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With those limitations in mind, here&amp;#8217;s what I came up with.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_declaring_the_task_io_protocol&quot;&gt;Declaring the task I/O protocol&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle is evolving fast and nowadays the idiomatic way to declare inputs and outputs of a task is to use the &lt;a href=&quot;https://docs.gradle.org/current/userguide/lazy_configuration.html&quot;&gt;lazy configuration API&lt;/a&gt;.
However, this isn&amp;#8217;t enforced and nobody prevents you from writing tasks which do not use this API.
As an implementor of a new integration mechanism, I can set the rules and actually restrict the scope to tasks which use this API, which has a number of advantages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Say that we want to write a task which computes the sum of two integers.
With the lazy configuration API, you need two &quot;properties&quot; corresponding to the input numbers:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;abstract class MyTask extends DefaultTask {
   abstract Property&amp;lt;Integer&amp;gt; getX(); // implementation is generated by Gradle
   abstract Property&amp;lt;Integer&amp;gt; getY();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The actual value is &quot;lazy&quot; in the sense that it can be set via a plugin, overriden in a build script, mapped from another property, etc.
For example, that the value of the &lt;code&gt;x&lt;/code&gt; property can be computed from the output of another task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;x.set(myOtherTask.outputFile.map { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The advantage of this is that Gradle can track the inputs and outputs of tasks for you and that you don&amp;#8217;t have to declare any explicit dependency between tasks, making the build less brittle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, once you&amp;#8217;re about to &lt;em&gt;execute&lt;/em&gt; a task, you don&amp;#8217;t really care about the &lt;code&gt;Property&amp;lt;&amp;#8230;&amp;#8203;&amp;gt;&lt;/code&gt; wrappers anymore: what matters are the actual values, that you can &lt;code&gt;get()&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;int x = getX().get();
int y = getY().get();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This often leads to some boilerplate code in task implementations.
In our case, the &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; integers are actually the only thing we care about to call our WASM function: we don&amp;#8217;t need to pass the richer &lt;code&gt;Provider&lt;/code&gt; type to the functions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s imagine that we have this function written in Rust:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern fn sum(x: i32, y: i32) -&amp;gt; i32 {
    x + y
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can see that the inputs of this function are integers and that it returns another integer: it&amp;#8217;s that simple.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, what if we could actually simplify the implementation of the Gradle task itself?
With all this in mind, I decided to prototype an annotation processor which would generate the boilerplate code for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To transform the Rust function above into a full Gradle task, &lt;a href=&quot;https://github.com/melix/gradle-wasm-plugin/blob/main/plugin/src/main/java/me/champeau/gradle/wasm/auto/SumIO.java&quot;&gt;all I have to write&lt;/a&gt; is a declaration of what I call its I/O protocol:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;@WasmProtocol(
        taskName = &quot;Sum&quot;,
        classpathBinary = &quot;demo_lib&quot;,
        functionName = &quot;sum&quot;
)
public interface SumIO {
    @Input
    Property&amp;lt;Integer&amp;gt; getX();

    @Input
    Property&amp;lt;Integer&amp;gt; getY();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This will generate a task of type &lt;code&gt;Sum&lt;/code&gt;, which will use a wasm binary found on classpath named &lt;code&gt;demo_lib&lt;/code&gt;, and use the function &lt;code&gt;sum&lt;/code&gt; from that binary as the task implementation.
That&amp;#8217;s it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that this protocol isn&amp;#8217;t declaring any output: that&amp;#8217;s a limitation of the prototype right now, which is inherently caused by this whole &quot;Gradle tasks are mostly generating files&quot; problem.
But we don&amp;#8217;t really care for now.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_more_realistic_example&quot;&gt;A more realistic example&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For my tests, I used 3 different functions: this &lt;code&gt;sum&lt;/code&gt; function, a &lt;code&gt;fib&lt;/code&gt; function (the Fibonacci suite function) and I wanted to try something more complicated like computing an md5 hash.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This, for example, is how I would define the protocol for the MD5 hashing function:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public interface HasherIO {
    @InputFile
    @PathSensitive(PathSensitivity.NAME_ONLY)
    RegularFileProperty getInputFile();

    @OutputFile
    RegularFileProperty getOutputFile();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Except that in this case, because the input is a file, I couldn&amp;#8217;t use my code annotation processor code generator yet (but it&amp;#8217;s planned).
Instead I wrote code to read the file manually, allocate WebAssembly memory buffers, in order to call the function which is implemented in Rust:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;#[no_mangle]
pub extern fn process(bytes: *const u8, len: usize) -&amp;gt; *const c_void {
    let data: &amp;amp;[u8] = unsafe { std::slice::from_raw_parts(bytes, len) };
    let mut hasher = Md5::new();
    hasher.update(data);
    let result = hasher.finalize_fixed();
    let pointer = result
        .to_vec()
        .as_ptr();
    mem::forget(pointer);

    pointer as *const c_void
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then all I need is to use this task in a build script. Let&amp;#8217;s see how it performs&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_webassembly_runtimes&quot;&gt;The WebAssembly runtimes&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I wrote 2 different implementations of the WASM integration runtime: the first one was pretty straightforward to write and makes use of &lt;a href=&quot;https://github.com/wasmerio/wasmer-java&quot;&gt;wasmer-java&lt;/a&gt;.
The second one took me significantly more time to implement and is using &lt;a href=&quot;https://www.graalvm.org/&quot;&gt;GraalVM&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Integrating &lt;a href=&quot;https://github.com/wasmerio/wasmer-java&quot;&gt;Wasmer&lt;/a&gt; was easy for different reasons:
1. it&amp;#8217;s just a library which you have to add to your classpath
2. it&amp;#8217;s relatively well documented&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;GraalVM was more complicated because:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;you actually need to run your program &lt;em&gt;on&lt;/em&gt; GraalVM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you need to install the WASM support separately (it&amp;#8217;s not downloadable as a regular Maven dependency, for example)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you still need to add the GraalVM polyglot API on classpath&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it&amp;#8217;s poorly documented at this stage (in particular, there&amp;#8217;s no documentation whatsoever on how to share memory between the Java host and the WASM guest)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Anyway, I think (but I haven&amp;#8217;t done it yet) that the GraalVM runtime will be easier to support I/O since it already offers the configuration options to let the WASM host access the host file system.
Wasmer doesn&amp;#8217;t support I/O yet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s talk about performance, now.
Disclaimer: this isn&amp;#8217;t proper benchmarking. The results you will see were obtained via functional testing of a plugin. There&amp;#8217;s a lot of variance, but they were reproducible.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_measuring_the_wasmer_runtime&quot;&gt;Measuring the wasmer runtime&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In short, the wasmer runtime is very promising: it&amp;#8217;s easy to setup and actually performs extremely well.
The API is not very Java friendly, but the &lt;a href=&quot;https://github.com/melix/gradle-wasm-plugin/tree/main/wasm-invoker&quot;&gt;abstraction layer I wrote (which supports both wasmer and GraalVM)&lt;/a&gt; makes it significanly easier.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are some results for a memoized Fibonacci, which compares a version I wrote in Java vs the one I wrote in Rust:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Memoized Fibonacci on wasmer&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Java fib(90) = 2880067194370816120
Took 3ms
Precompiled Rust fib(90) = 2880067194370816120
Took 366μs&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The WASM version compiled from Rust is already faster than the Java version!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s see how it performs when hashing a MD5 file (remember that for this use case, I&amp;#8217;m actually passing a &lt;em&gt;byte array&lt;/em&gt; to the WASM program, not a file):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Hashing a 4MB file on wasmer&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;hash from Java is 49DFDCEF6751973A236D35401B6CBFC8
Took 64ms
hash from Rust is 49DFDCEF6751973A236D35401B6CBFC8
Took 58ms&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again, the WASM version is still faster!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On both operations, the WASM binary performs better than the pure Java version. However, there&amp;#8217;s a catch: in order to reach that level of performance, the WASM binary has to be precompiled to a native binary by wasmer.
This, already takes time. If you include this in the whole picture, the numbers are different: 36ms for Fibonacci (compared to 3ms in Java, 10x slower).
However, this is in practice not a big deal since those binaries can actually be cached, meaning that if we have to call them multiple times, or from different builds, we can actually fetch them from the cache.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All in all, it means that the wasmer runtime is very fast and integrates quite well with Java.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_measuring_the_graalvm_runtime&quot;&gt;Measuring the GraalVM runtime&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.oracle.com/en/graalvm/enterprise/20/docs/reference-manual/wasm/&quot;&gt;WebAssembly support for GraalVM&lt;/a&gt; is still experimental.
However, it has the advantage of taking advantage of the Truffle API, which promises better integration between languages and, eventually, better performance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my case, that wasn&amp;#8217;t quite true. Again as usual don&amp;#8217;t trust benchmarks, but here are the numbers:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Memoized Fibonacci on wasmer&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Java fib(90) = 2880067194370816120
Took 3ms
Precompiled Rust fib(90) = 2880067194370816120
Took 21ms&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This time, the WASM code is significantly slower. The explanation is probably that contrary to the wasmer runtime, the WASM binary has to be parsed and transformed into a model that the Truffle API can understand, and as far as I could tell, this is not cacheable. However, this isn&amp;#8217;t the only explanation, as we can see with the hash example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Hashing a 4MB file on GraalVM&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;hash from Java is 49DFDCEF6751973A236D35401B6CBFC8
Took 57ms
hash from Rust is 49DFDCEF6751973A236D35401B6CBFC8
Took 407ms&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again we can see that the performance is significantly worse with GraalVM.
I must again say that maybe I&amp;#8217;m not using the API properly.
In particular, I have found no better way to pass the &lt;code&gt;byte[]&lt;/code&gt; to the WASM memory model other than &lt;a href=&quot;https://github.com/melix/gradle-wasm-plugin/blob/main/wasm-invoker/src/main/java/me/champeau/wasm/invocation/internal/GraalVMInvoker.java#L99-L103&quot;&gt;byte by byte!&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_what_weve_learnt&quot;&gt;What we&amp;#8217;ve learnt&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, we&amp;#8217;ve seen that we can use a wasm binary in Gradle as the implementation of a task.
This binary can be written in any language which supports compiling to WebAssembly.
In my [test project], I have written tasks in 2 different languages: &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; and &lt;a href=&quot;https://github.com/AssemblyScript/assemblyscript&quot;&gt;AssemblyScript&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We&amp;#8217;ve seen that we can integrate WASM binaries using 2 different &quot;runtimes&quot;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/wasmerio/wasmer-java&quot;&gt;Wasmer&lt;/a&gt;, which is using JNI and compiles, as far as I understand, WebAssembly binaries to native code&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.graalvm.org/&quot;&gt;GraalVM&lt;/a&gt;, which is a different Java Virtual Machine, which usually performs extremely well with Java, and provides a &lt;a href=&quot;https://www.graalvm.org/reference-manual/polyglot-programming/&quot;&gt;Polyglot runtime&lt;/a&gt; leveraging the &lt;a href=&quot;https://www.graalvm.org/graalvm-as-a-platform/language-implementation-framework/&quot;&gt;Truffle API&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As of today, the Wasmer version performs significantly better and WASM functions can be executed even faster than Java code!
The GraalVM version is still experimental and performs quite poorly compared to using native Java code. It&amp;#8217;s also more painful to test because it&amp;#8217;s not enough to install GraalVM: you also have to install components separately, which is not build friendly, nor CI friendly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next step for me is to try to integrate more directly with the file system: at the current stage, none of the approaches is suitable for Gradle as we need to read and write files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Also, one has to keep in mind that it&amp;#8217;s pretty rare that you&amp;#8217;d like to integrate in a build arbitrary code like this: in general, you want to call external tools (&lt;code&gt;javac&lt;/code&gt;, &lt;code&gt;gcc&lt;/code&gt;, &amp;#8230;&amp;#8203;).
Nevertheless, this experiment is quite fun and I&amp;#8217;m going to experiment more with this annotation processing API, which, I think, would be valuable in any case.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>The problem with Gradle: really?</title>
      <link>https://melix.github.io/blog//2021/01/the-problem-with-gradle.html</link>
      <pubDate>Wed, 6 Jan 2021 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2021/01/the-problem-with-gradle.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Disclaimer: I&amp;#8217;m a former Groovy committer and a Gradle Inc. employee.
However, I started using Gradle long before I joined Gradle, and I have quite some experience with Java build tools: I started with Ant, but I also used Maven quite a lot, then fell in love with Gradle, for many reasons.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bruceeckel.com/2021/01/02/the-problem-with-gradle/&quot;&gt;A blog post from Bruce Eckel&lt;/a&gt; made quite some noise on Reddit (no wonder, Bruce is a guru!).
It&amp;#8217;s not the first time I read comments about Gradle, this article in itself is balanced and not that negative.
Most of the criticism is on the title itself, which is misleading and looks like a clickbait.
One can easily be retweeted without actually reading the details, and most importantly the conclusion.
Also, it doesn&amp;#8217;t compare with what you&amp;#8217;d have to do with &lt;em&gt;other&lt;/em&gt; build tools, which is important to draw good conclusions.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_what_makes_gradle_different&quot;&gt;What makes Gradle different?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At the core of this blog post is the thing that the &quot;big picture&quot; of Gradle is unclear.
There are several things to say here.
First of all, Gradle is not a new, shiny toy to play with: it was born more than 10 years ago, and saw its v1.0 release on Jun 12, 2012.
Second, there&amp;#8217;s not a &quot;single&quot; problem with Gradle: there are different problems, some more important than the others, but there are also many, many benefits.
As such, one should draw a complete picture, which is sometimes hard for build tools, something that developers tend to underestimate, in particular in terms of impact on developer productivity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle is designed to improve developer productivity which is achieved via incremental builds, incremental tasks, parallel execution, reproducibility and many other features.
Let&amp;#8217;s put it this way: if you look at Gradle from the DSL point of view, that is, the look and feel, instead of its capabilities, the engine, you will miss the most interesting parts.
The beauty of Gradle is not in its &quot;flexibility&quot; offered because it uses configuration as code: it&amp;#8217;s the engine which is designed to model software properly and optimizes building software.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_do_you_have_to_know_everything&quot;&gt;Do you have to know everything?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bruce states that with Gradle, &quot;To do anything you have to know everything&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While the formula is elegant, this is a bold statement: this simply doesn&amp;#8217;t align with the reality of the Gradle ecosystem, our community and larger user base.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is true, however, is that the learning curve of Gradle is higher than with other build tools (say, Maven for example).
I always said that the learning curve of Gradle is difficult, but once you get it, the benefit is just amazing: we have customers who tell stories about dramatic productivity boosts after migrating to Gradle, simplified maintenance and coordination of large development teams via corporate plugins.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the reasons is that Gradle is fundamentally different from other build tools: it focuses on modeling software components and their relationships, and as such it can be considered as a language for building &lt;em&gt;any&lt;/em&gt; kind of application. It raises the concept of convention over configuration to another level.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s no surprise that Gradle has been successfully used to build software in various ecosystems: the JVM, where it&amp;#8217;s born (with Java, Groovy, Scala in particular), but also native development (take a look at &lt;a href=&quot;https://nokee.dev/&quot;&gt;Nokee&lt;/a&gt; if you are interested), Go (&lt;a href=&quot;https://github.com/gogradle/gogradle&quot;&gt;Go Gradle&lt;/a&gt;), &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some ecosystems actually build on top of unique features of Gradle, in particular in terms of dependency management: Android (with multiple flavors of libraries and applications) or Kotlin in particular (with Kotlin Multiplatform).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Why is that? Gradle is an execution engine optimized for build workflows, with intelligence about how to build things incrementally.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nonetheless, improving the experience of first time users is something the Gradle team focuses on, as we will see below.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tasks_vs_dependencies_a_simplistic_view&quot;&gt;Tasks vs dependencies: a simplistic view&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bruce says that any build system is basically the combination of two essential ingredients: &lt;em&gt;tasks&lt;/em&gt; and &lt;em&gt;dependencies&lt;/em&gt;, where dependencies are seen as artifacts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That is not quite correct in case for Gradle: Gradle is responsible for wiring units of work together, either through explicit or implicit dependencies.
It&amp;#8217;s important to understand that &quot;dependency&quot; here has a wider meaning: it&amp;#8217;s something which is required to be able to execute a unit of work.
There is, technically speaking, no difference between an external and an internal dependency. What matters is that we have units of work, which have inputs and outputs.
The role of Gradle is to wire things so that everything is ordered properly and optimized for execution (parallelism, caching, &amp;#8230;&amp;#8203;).
It&amp;#8217;s a mistake to think that there are only tasks and dependencies (files, mostly): there are work units, inputs and outputs.
A task (say, &lt;code&gt;JavaCompile&lt;/code&gt;) is just &lt;em&gt;one kind&lt;/em&gt; of work unit, but that&amp;#8217;s not the only one. Here are some other kind of work units: transforming artifacts (for example, transform a &lt;em&gt;jar&lt;/em&gt; into something else before it is consumed), downloading a toolchain, uploading an artifact to the build cache, &amp;#8230;&amp;#8203; A task itself can be splitted into several work units in order to maximize incrementality and parallelism.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A lot of the criticism we see on Gradle is because there&amp;#8217;s a mismatch between the mental model of what Gradle is, and the surface, which is the language(s) it uses to configure the actual model.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A lot of the confusion comes from the fact that while Gradle has a vision, it should be better shared and explained.
It&amp;#8217;s also victim of its age which means success: the road towards fine grained execution, safe parallelism, configuration, &amp;#8230;&amp;#8203; is hard and there are some APIs which are sub-optimal for this, and &lt;a href=&quot;https://docs.google.com/forms/d/e/1FAIpQLSc9aQrjjsxVqXDkYR35ExeiI1yEIksRXVtN6asuaem084l3aA/viewform&quot;&gt;maintaining backwards compatibility is a day-to-day challenge&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s explain a bit what Gradle has to do, when you say that you want to execute a &lt;em&gt;task&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;configure the task (execute its &lt;em&gt;configuration phase&lt;/em&gt;), which means executing plugins which configure the default values, use your configuration, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compute the &lt;em&gt;dependencies&lt;/em&gt; of the task, which can either be explicit (typically the &lt;code&gt;dependsOn&lt;/code&gt; clause) or &lt;em&gt;implicit&lt;/em&gt; (because you configured a task input as the output of another task, typically): this is basically a directed graph resolution engine, which is very fine grained and where each node is a unit of work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and finally executes the nodes of the graph in an optimized way&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Historically, Gradle has separated the &lt;em&gt;configuration phase&lt;/em&gt; from the &lt;em&gt;execution phase&lt;/em&gt;, but it doesn&amp;#8217;t have to be that way: as soon as the inputs of a task are ready, we should be able to execute it, and we shouldn&amp;#8217;t have to wait for the configuration of other tasks to be ready to do it.
Also Gradle made it easy, in the beginning, to &lt;em&gt;inline&lt;/em&gt; the definition of tasks, including their execution phase, in a build script, but it is, for quite some time, considered a bad design principle: don&amp;#8217;t write &lt;em&gt;build logic&lt;/em&gt; in build scripts. The whole blog post from Bruce never mentions this term a single time: &lt;a href=&quot;https://docs.gradle.org/current/userguide/custom_plugins.html&quot;&gt;write plugins&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Despite our efforts, lots of resources on the web still focus on how to declare tasks, how flexible Gradle is, without taking time to leverage good engineering practices. In Java nobody writes a giant single class with all the logic &lt;em&gt;and&lt;/em&gt; the data as code, right? So don&amp;#8217;t do it in your build, that&amp;#8217;s as simple as that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s be honest: it&amp;#8217;s partly our fault, and for that I agree with Bruce: the documentation of Gradle is huge and things can be made better, especially for beginners.
It&amp;#8217;s also true that the docs contain &lt;em&gt;outdated patterns&lt;/em&gt; and it&amp;#8217;s often very difficult to realize that you have outdated info in thousands of pages of docs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There is, however, a good amount of resources for beginners:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;samples: &lt;a href=&quot;https://docs.gradle.org/current/samples/index.html&quot; class=&quot;bare&quot;&gt;https://docs.gradle.org/current/samples/index.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;guides (slowly replaced with the samples above): &lt;a href=&quot;https://gradle.org/guides/&quot; class=&quot;bare&quot;&gt;https://gradle.org/guides/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;free trainings: &lt;a href=&quot;https://gradle.com/training/&quot; class=&quot;bare&quot;&gt;https://gradle.com/training/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;webcasts: &lt;a href=&quot;https://gradle.com/blog/tag/webcast/&quot; class=&quot;bare&quot;&gt;https://gradle.com/blog/tag/webcast/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_deconstructing_the_myth&quot;&gt;Deconstructing the myth&lt;/h3&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We are still in the early days of the “adding a build system atop an existing language” paradigm. Gradle is an experiment in this paradigm, so we expect some sub-optimal choices. However, by understanding its issues you might have less frustration learning Gradle than I did.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; Bruce Eckel&lt;br&gt;
&lt;cite&gt;The Problem With Gradle&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is incorrect. Thinking that Gradle is just about calling methods is the wrong mental model. Thinking that Gradle is &quot;programming a build&quot; is wrong. Gradle uses a programming language as a foundation for &quot;configuration as code&quot;, but it is &lt;em&gt;really&lt;/em&gt; about configuration, not &lt;em&gt;programming&lt;/em&gt;. Surely a programming language is interesting to use in the &quot;configuration as code&quot; paradigm, but focusing on that aspect and assuming that it works as a general purpose language is wrong and will inevitably lead to confusion.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle is also &lt;em&gt;not&lt;/em&gt; an experiment: it&amp;#8217;s the most advanced tool you can find in this area, and it works &lt;em&gt;because&lt;/em&gt; the language builds on top of an engine which is made to execute workflows.
A number of build tools, including modern ones, are only fast because they put the maintenance and optimization burden on the build author: declare everything, re-generate build scripts, etc.
We, in the Gradle team, think that we can be more correct, more performant &lt;em&gt;without&lt;/em&gt; having to compromise on user experience.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We even had teams challenging us on performance with modern tools like Bazel, and we proved that with unique features like &lt;a href=&quot;https://docs.gradle.org/current/userguide/configuration_cache.html#header&quot;&gt;configuration caching&lt;/a&gt;, Gradle was able to outperform it in almost all scenarios: you get the benefit of terse, maintainable scripts, with performance. win-win.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, it&amp;#8217;s time to deconstruct some misconceptions of the blog post, because as long as this message is propagated, we will not achieve what should be the focus of our industry: safer, faster, reproducible builds for everyone.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_1_youre_not_configuring_youre_programming&quot;&gt;1. You&amp;#8217;re not Configuring, You’re Programming&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You should see &lt;em&gt;Gradle build scripts&lt;/em&gt; as &lt;em&gt;configuration scripts&lt;/em&gt;, which actually configure a &lt;em&gt;model&lt;/em&gt;.
The surface is a DSL, a language, but what you do, what you &lt;em&gt;should do&lt;/em&gt;, is to declaratively model your software.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, this Groovy script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
   id &apos;java-library&apos;
}

dependencies {
    api &apos;org.springframework:spring-core:2.5.6&apos;
    implementation &apos;org.apache.commons:commons-lang3:3.3.10&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Is a build script which configures a library written in Java, while this build script, written in Kotlin, configures a different kind of software component:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;plugins {
    id(&quot;org.gradle.presentation.asciidoctor&quot;)
}

presentation {
    githubUserName.set(&quot;melix&quot;)
    githubRepoName.set(&quot;gradle-6-whats-new&quot;)
    useAsciidoctorDiagram()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which is actually a &lt;code&gt;reveal.js&lt;/code&gt; slide deck, built with Gradle! This is the &lt;em&gt;full&lt;/em&gt; build script for this, and it&amp;#8217;s extremely important to realize that: the &quot;code&quot; that you get shouldn&amp;#8217;t have any custom tasks, in particular: all of the complexity, which is nothing more than the &quot;model&quot;, is hidden in a &lt;em&gt;plugin&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I strongly encourage you to read my &lt;a href=&quot;https://melix.github.io/blog/2019/11/gradle-scripting.html&quot;&gt;Gradle myth busting: scripting&lt;/a&gt; blog post which describes exactly that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, you can watch this 10 minute video I made about writing idiomatic build scripts:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/MaansFoPHKg&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What it means is that while Gradle build scripts are &lt;em&gt;executed&lt;/em&gt;, this is code which &lt;em&gt;configures the model&lt;/em&gt;, so you&amp;#8217;re &quot;programming the configuration&quot;, if you will.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_2_groovy_is_not_java&quot;&gt;2. Groovy is Not Java&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There&amp;#8217;s not much to say here, because it barely has anything to do with Gradle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will notice that when I showed build scripts above, I showed a &lt;em&gt;Groovy&lt;/em&gt; build script and a &lt;em&gt;Kotlin&lt;/em&gt; one. It&amp;#8217;s important to notice that Gradle allows both, because under the hood, it&amp;#8217;s an API.
As I said, Gradle provides a foundation for building software components, a dependency resolution engine, an execution engine.
&lt;em&gt;Plugins&lt;/em&gt; are at the core of the system and are responsible for building &lt;em&gt;models&lt;/em&gt; of software we build: a Java library is different from an Android application, so there&amp;#8217;s &lt;em&gt;no reason&lt;/em&gt; to have the same source layout, for example.
The fact that Gradle uses Groovy as a language to do its configuration is an &lt;em&gt;implementation detail&lt;/em&gt;.
I think it&amp;#8217;s a mistake to consider that you need a programming language to do what Gradle does: it helps, and lots of people actually appreciate Gradle&amp;#8217;s flexibility in that regard, but it&amp;#8217;s not what you should focus on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Both Groovy and Kotlin have pros and cons. If you use Intellij IDEA, for example, the Kotlin DSL has very good arguments and makes this model completely visible: completion is available, you don&amp;#8217;t have to &quot;guess&quot; what to type: depending on the plugins you apply, you get the configuration blocks you need, and nothing more!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To come back to this section, a common misconception is that Gradle is written in Groovy. It&amp;#8217;s not. Gradle is written in Java, mostly. There&amp;#8217;s a lot of Groovy code in Gradle for testing (we use Spock, in particular), but we also have Kotlin code. The build scripts, however, use Groovy or Kotlin.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The DSL design definitely was influenced by Groovy, though, that&amp;#8217;s very true.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_3_gradle_uses_a_domain_specific_language&quot;&gt;3. Gradle Uses a Domain-Specific Language&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes it does. I should say it&amp;#8217;s an &quot;extensible&quot; DSL. But when I&amp;#8217;m reading this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;How helpful is this DSL syntax, really? I have to translate it into function calls in my head when I read it. So for me it’s additional cognitive overhead which is ultimately a hindrance. The DSL operations can all be done with function calls, and programmers already understand function calls.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m thinking that this is again seeing the problem from the wrong angle. You should &lt;em&gt;not&lt;/em&gt; see this as function calls, or code being executed. You should see this as a model being configured. You can&amp;#8217;t, actually, assume &lt;em&gt;when&lt;/em&gt; this code is going to be called (because, we have configuration avoidance, for example). So a DSL is really what it means: it&amp;#8217;s a language meant to configure the model, nothing more. By trying to interpret &lt;em&gt;how&lt;/em&gt; Gradle does this, you&amp;#8217;re actually distracted from what matters: what are you trying to build?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_4_there_are_many_ways_to_do_the_same_thing&quot;&gt;4. There are Many Ways to do the Same Thing&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This one is one of my favourites. I always read &quot;there are too many ways to do the same thing&quot;. Sure there are. Just like in Java, can you tell me how many ways you can write a loop? Let&amp;#8217;s see&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;indexed loop&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;for (int i=0; i&amp;lt;items.length(); i++) {
   ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;foreach loop&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;for (String item: items) {
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;while loop&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;Iterator&amp;lt;String&amp;gt; it = items.iterator();
while (it.hasNext()) {
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;(not mentioning the &lt;code&gt;do&amp;#8230;&amp;#8203;while&lt;/code&gt; variant)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;streams&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;items.stream()
   .map(...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;streams again&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;items.forEach(...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Does anyone complain that Java has too many ways to do the same thing? Certainly not, because there are different reasons: historical (good old loops came first), performance (sometimes streams are not that fast), semantic (iterator lets you delete things while iterating), &amp;#8230;&amp;#8203; Even Python has many ways to do the same thing. Isn&amp;#8217;t it the case when you&amp;#8217;re free to write code? Some consider it&amp;#8217;s a reason alone &lt;em&gt;not to use Gradle&lt;/em&gt;. It would be a mistake, because you don&amp;#8217;t stop programming Java because it has too many ways to write a loop.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The thing is &quot;use the right tool for the right job&quot;. Gradle is no different. Except that there are not so many ways to do things 😉 Some are legacy patterns, and there we need to do better at documenting, some are just because people are trying to write code in their build scripts when &lt;em&gt;they shouldn&amp;#8217;t&lt;/em&gt; (write plugins!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I should mention that we started something called the &lt;strong&gt;idiomatic Gradle&lt;/strong&gt; project for these excellent reasons.
The goal is to encourage best practices, document the most idiomatic way to do something, covering multiple use cases and their differences.
There will be a blog post from the team about this project, in the meantime you can already read some results:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a sample showing how to build &lt;a href=&quot;https://docs.gradle.org/current/samples/sample_building_java_applications_multi_project.html&quot;&gt;multi-project Java applications&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;documentation about &lt;a href=&quot;https://docs.gradle.org/6.8-rc-5/userguide/structuring_software_products.html&quot;&gt;structuring larger builds&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a &lt;a href=&quot;https://jjohannes.github.io/joker-conf-2020/#/&quot;&gt;presentation&lt;/a&gt; from my colleague Jendrik Johannes about idiomatic Gradle at JokerConf&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, we have ongoing conversations about a &quot;strict mode&quot; in Gradle to actually enforce some language constructs, or even a different DSL, to limit what you can actually do in a build script.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_5_magic&quot;&gt;5. Magic&lt;/h4&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Any sufficiently advanced technology is indistinguishable from magic.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; Arthur C. Clarke&lt;br&gt;
&lt;cite&gt;Profiles of the Future: An Inquiry Into the Limits of the Possible&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This whole section is basically about understanding the separation between &lt;em&gt;configuration&lt;/em&gt; and &lt;em&gt;execution&lt;/em&gt; phases, but really what bothers me most is that it&amp;#8217;s much easier to grasp if you just &lt;em&gt;don&amp;#8217;t write inline tasks into build scripts&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, if I write, in a plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public abstract class ProcessTemplates extends DefaultTask {

    @Input
    public abstract Property&amp;lt;TemplateEngineType&amp;gt; getTemplateEngine();

    @InputFiles
    public abstract ConfigurableFileCollection getSourceFiles();

    @OutputDirectory
    public abstract DirectoryProperty getOutputDir();

    @TaskAction
    void execute() { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then the separation between &lt;em&gt;inputs&lt;/em&gt; (properties annotated with &lt;code&gt;@InputXXX&lt;/code&gt;), outputs &lt;code&gt;@OutputDirectory&lt;/code&gt; and the actual task execution &lt;code&gt;@TaskAction&lt;/code&gt; is obvious.
More importantly, if you do this Gradle helps you by providing you guidance on what annotations to use, how to make it compatible with caching, etc for free (via embedded linting).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I repeat, nobody should every inline &lt;em&gt;build logic&lt;/em&gt; in a build script. Nobody.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Accidentally, the scripts Bruce shows in this section are using Groovy, which, for backwards compatibility reasons, uses &lt;em&gt;eager configuration APIs&lt;/em&gt;.
If you use Kotlin scripts, all the task creation, registration, is done lazily, avoiding unnecessary configuration. You can do this in Groovy too, if you use the &lt;a href=&quot;https://docs.gradle.org/current/userguide/task_configuration_avoidance.html&quot;&gt;configuration avoidance APIs&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_5bis_the_lifecyle&quot;&gt;5bis, the lifecyle&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This section again discusses &lt;em&gt;configuration&lt;/em&gt; vs &lt;em&gt;execution&lt;/em&gt;. Just a terminology comment here: a &lt;em&gt;lifecyle&lt;/em&gt; in Gradle and other build tools is a different thing. See my other &lt;a href=&quot;https://melix.github.io/blog/2018/09/gradle-lifecycle.html&quot;&gt;Gradle myth busting: lifecyle&lt;/a&gt; blog post for reference.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_other_issues&quot;&gt;Other Issues&lt;/h4&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The Gradle documentation assumes you already know a lot.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes, and no. The Gradle documentation is large and as I said in the intro, we do have sections for beginners. What is true, and I&amp;#8217;m quite mad about this, is that our docs layout is terrible, and that good documentation is very difficult to find out.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We also started to rewrite sections so that they are &lt;em&gt;use case centered&lt;/em&gt;, see the &lt;a href=&quot;https://docs.gradle.org/current/userguide/dependency_management.html&quot;&gt;dependency management&lt;/a&gt; docs for example.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Slow startup times&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In most cases, &quot;slow startup times&quot; actually refer to &quot;slow configuration times&quot;. This is in general because of too much code being executed at configuration time. That&amp;#8217;s why we have &lt;a href=&quot;https://docs.gradle.org/current/userguide/task_configuration_avoidance.html&quot;&gt;configuration avoidance APIs&lt;/a&gt; and that you can possibly use &lt;a href=&quot;https://scans.gradle.com&quot;&gt;build scans&lt;/a&gt; which tell you that you are doing too much at configuration time.
However, with the experimental &lt;a href=&quot;https://docs.gradle.org/current/userguide/configuration_cache.html&quot;&gt;configuration cache&lt;/a&gt;, those configuration time issues should soon be a thing of the past.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Be careful with some (very) popular plugins: some plugin authors just don&amp;#8217;t realize that the way they configure builds, reach to other projects or perform cross-configuration has a significant impact on build performance, and therefore user experience.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All that said, we&amp;#8217;re doing even more: I mentioned the &lt;a href=&quot;https://docs.gradle.org/current/userguide/configuration_cache.html&quot;&gt;configuration cache&lt;/a&gt; earlier. This is still work in progress, but we have amazing results with this. Very large multi-project builds are configured very quickly. We&amp;#8217;re working with customers and the Android team on this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s not that easy to discover Gradle’s abilities, and there are so many abilities that you often don’t know what’s possible&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Oh yes. Oh, yes. Gradle is probably the most advanced build tool of the market. It has dozens of features, including unique features you don&amp;#8217;t find in any other build tool. They are hardly discoverable. We need more advocacy on those, and make them more visible. I am not sure how we can do this, honestly.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_now_that_i_get_it&quot;&gt;Now That I Get It&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The conclusion of the blog post is quite positive. However it mentions IDE support. I should say, despite being a Groovy developer, I use it everyday, that if you use IntelliJ IDEA in particular, discovering Gradle using the Kotlin DSL is &lt;em&gt;much&lt;/em&gt; easier. You get smart, contextual, IDE completion, which really helps in understanding how Gradle works. There are drawbacks in using Kotlin build scripts, in particular because Kotlin compilation is painfully slow (Scala developers would understand). Independently of the JetBrains team, which is working on performance of the compiler, &lt;a href=&quot;https://docs.gradle.org/6.8-rc-5/release-notes.html#kotlin-dsl-performance&quot;&gt;Gradle 6.8 will also provide some nice Kotlin DSL performance improvements&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post I have commented on some remaining misconceptions about Gradle, which are still visible in Bruce&amp;#8217;s blog post. However, there&amp;#8217;s no blocker there. I would however really encourage you to go the idiomatic Gradle route and try to follow modern Gradle design principles. If you have time, here&amp;#8217;s a talk I gave recently at the Madrid Groovy User Group about modernizing the Groovy build, I think it summarizes quite a lot why a number of the patterns described in Bruce&amp;#8217;s blog post are outdated and shouldn&amp;#8217;t be promoted:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/HXAV9pL5Rf8&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Dependabot and automated dependency upgrades</title>
      <link>https://melix.github.io/blog//2020/10/about-dependabot.html</link>
      <pubDate>Sun, 11 Oct 2020 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2020/10/about-dependabot.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://dependabot.com/&quot;&gt;Dependabot&lt;/a&gt; starts with a great idea: the state of our industry, in terms of dependency management, is sad.
In particular, maintaining dependencies up-to-date is difficult and while some solutions exist, the vast majority of projects are out of date.
This isn&amp;#8217;t a big deal for bugfixes and feature updates, but it is clearly a problem for security issues.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, any kind of automation to make the situation better is a good idea.
I am in deep empathy with people working in this area: this is a difficult problem and there are no perfect solutions: as an example, in order to improve security of builds and reduce the risks of attacks via the toolchain, &lt;a href=&quot;https://docs.gradle.org/current/userguide/dependency_verification.html&quot;&gt;Gradle introduced dependency verification&lt;/a&gt; as a first-class citizen.
We deeply care about security and definitely support any attempt to make things better in this area.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The genius idea about &lt;a href=&quot;https://dependabot.com/&quot;&gt;Dependabot&lt;/a&gt; is that it does it at scale &lt;strong&gt;and submits pull requests&lt;/strong&gt; that you just have to review and merge if everything goes ok.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The best example in the Java ecosystem happened yesterday: the JUnit team fixed a &lt;a href=&quot;https://github.com/junit-team/junit4/security/advisories/GHSA-269g-pwp5-87pp&quot;&gt;security vulnerability in JUnit 4.13&lt;/a&gt;.
At first, you might wonder what kind of security problems you can have with a testing framework, which, by definition, just like a build tool, runs any arbitrary code on your machine.
The reality is that most people are unaffected by this problem: it would only be the case if your tests write sensitive data (like credentials) in a shared environment, or that you somehow expose whatever is written in the test directory to the outside world.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nevertheless, because it&amp;#8217;s a CVE, Dependabot submitted automated pull-requests to all projects using JUnit 4 and &lt;a href=&quot;https://github.com/search?o=desc&amp;amp;q=Bump+junit+from+to+4.13.1+GHSA-269g-pwp5-87pp&amp;amp;s=&amp;amp;type=Issues&quot;&gt;Dependarmaggedon happened&lt;/a&gt;: tens of thousands of pull requests.
This might sound cool, a security fix needs to be fixed, but I find this noisy, and in the end dangerous.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here&amp;#8217;s why.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_automatic_detection&quot; class=&quot;sect0&quot;&gt;Automatic detection&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://dependabot.com/&quot;&gt;Dependabot&lt;/a&gt; is as good as an automated tool can be.
I mean that its &lt;em&gt;implementation&lt;/em&gt;, at least in the Java and JVM ecosystem in general, is too simplistic and that it&amp;#8217;s inherently &lt;strong&gt;wrong&lt;/strong&gt;.
I don&amp;#8217;t have the expertise to tell if it&amp;#8217;s different in the other supported ecosystems (Go) but I suspect a lot of the problems I&amp;#8217;m going to describe here exist also in those ecosystems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In practice, Dependabot is nothing more than a search and replace engine: it looks into some particular files that it knows about (think &lt;code&gt;pom.xml&lt;/code&gt;), looks for some patterns, then tries to identify dependency coordinates and eventually replaces them. I&amp;#8217;m simplifying a bit, because it does some interpretation of the versions it finds, for example to match version ranges, but that&amp;#8217;s roughtly how it works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, it will identify this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;dependency&amp;gt;
   &amp;lt;group&amp;gt;junit&amp;lt;/group&amp;gt;
   &amp;lt;name&amp;gt;junit&amp;lt;/version&amp;gt;
   &amp;lt;version&amp;gt;4.13&amp;lt;/version&amp;gt;
   &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and it will replace the &lt;code&gt;4.13&lt;/code&gt; with &lt;code&gt;4.13.1&lt;/code&gt;, then submit a PR for you to review. WIN!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes, and no. Because this is extremely easy to defeat.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, as I said, it only looks for known files. For Maven, it&amp;#8217;s pretty simple, there&amp;#8217;s only one place to look for: &lt;code&gt;pom.xml&lt;/code&gt; files, but for other build tools, like Gradle, Ivy, Ant, Bazel, Pants, &amp;#8230;&amp;#8203; that&amp;#8217;s not the case: dependencies can be declared in different files, not all named the same. Dependency versions can be separate (in properties files) or inherited from context (parent POMs, platforms, &amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A more complete strategy is to look for patterns too, like &lt;code&gt;&lt;strong&gt;.gradle&lt;/code&gt;, but then, they also miss the &lt;code&gt;&lt;/strong&gt;.gradle.kts&lt;/code&gt; files (they do), or the plugins which can contribute dependencies.
In short: it&amp;#8217;s a whack-a-mole game.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One must think that it&amp;#8217;s not a big deal, because catching &lt;em&gt;some cases&lt;/em&gt; is better than not catching at all, and I agree, but that&amp;#8217;s not the expectation when you read what the tool promises.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, any tool which tries to parse build files and tries to interpret its model based on string evaluations is doomed to fail.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even if it manages to catch some problems, things can go wrong. As an example, here&amp;#8217;s what we got at Gradle for this JUnit upgrade:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/dependabomb.jpg&quot; alt=&quot;dependabomb&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For a &lt;strong&gt;single repository&lt;/strong&gt;, it created &lt;strong&gt;dozens&lt;/strong&gt; of individual pull requests to ask us to upgrade.
That&amp;#8217;s nice of you, Dependabot, but it&amp;#8217;s totally missing the point: this repository contains generated code, used in performance testing.
The way the code is layout, the repetition of dependency declarations, etc, everything is intentional.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you put apart the fact that Dependabot could have created a single pull request for all dependencies, instead of creating hundreds, it highlights a general problem with those automated detection tools:&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_context_matters&quot; class=&quot;sect0&quot;&gt;Context matters!&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At Gradle, we often receive emails from security teams telling us things like: &quot;The Gradle distribution contains a dependency on this X library which has vulnerability Y&quot;.
However, in almost all cases we&amp;#8217;ve investigated, this was a no issue for us.
Because of the nature of Gradle, the fact that by definition it runs arbitrary code on a machine, most vulnerabilities are not a problem in this environment: context matters.
What&amp;#8217;s more, even if your tool uses a library that has a critical vulnerability (we use Jackson for example, which had a number of thems recently), it doesn&amp;#8217;t mean that your code &lt;strong&gt;exercises the path which is vulnerable&lt;/strong&gt;: context matters!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s not harmful to upgrade, but it creates a lot of noise.&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_wrong_impression_of_security&quot; class=&quot;sect0&quot;&gt;Wrong impression of security&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But the biggest problem with such tools, and again I&amp;#8217;m using Dependabot as an example, is that they &lt;strong&gt;give a wrong impression of security&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As I explained, Dependabot will basically read your POM files, or Gradle files, or whatever build tool files you use, and &lt;em&gt;assume that the version it reads is the version which is going to be used&lt;/em&gt;.
We, as developers, and even more as build tool authors, know that this is wrong: the dependencies you declare are rarely the ones you resolve.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s the reason why tools like NPM (Javascript), Gradle (multi-language) or Cargo (Rust) make use of &lt;a href=&quot;https://docs.gradle.org/current/userguide/dependency_locking.html&quot;&gt;dependency locking&lt;/a&gt;.
Dependency locking is a concept which helps with build reproducibility.
Say, for example, that you write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
   implementation &apos;org.mylib:awesome:[1.0, 2[&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that Gradle can pick whatever version of &lt;code&gt;awesome&lt;/code&gt; as long as it&amp;#8217;s in the range.
This is a typical declaration for semantic versioning, when you expect a library to be upgradable up to the next major.
In Gradle you can even improve this by explaining what version you prefer in the range, if nobody else cares:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;dependencies {
   implementation(&apos;org.mylib:awesome&apos;) {
      version {
          require &apos;[1.0, 2[&apos;
          prefer &apos;1.3&apos;
      }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, ranges come at a price: if a new dependency version is released, your build would suddenly start using this new version, which breaks reproducibility in case you checkout old code, for example, for a bugfix.
Therefore, as soon as you use ranges (and by extension any &lt;em&gt;dynamic dependency version&lt;/em&gt;), you should use it with &lt;em&gt;dependency locking&lt;/em&gt;.
Dependency locking will make sure that whatever version of a library resolved at time T is used at time T+N even if a new version is out.
It does so by writing the result of the dependency resolution process in a lock file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Upgrading dependencies becomes an intentional process that you do from time to time by generating a new lock file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is the relationship with tools like Dependabot?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By using the versions you &lt;em&gt;declare&lt;/em&gt;, they have absolutely no guarantee that the versions you resolve are &lt;em&gt;not vulnerable&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the example above, imagine that I use range &lt;code&gt;[1.0, 2[&lt;/code&gt; and that I&amp;#8217;m resolving 1.3.
At some point in time, version 2.1 is released and is vulnerable.
You could imagine that because you used a range and that 2.1 is out of the range, you are safe.
That&amp;#8217;s what those tools would assume, but they would be wrong: the reality is that despite this declaration, by the play of conflict resolution (Ivy, Gradle, &amp;#8230;&amp;#8203;) or ordering (Maven), a totally different version can be selected, even 2.1!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again there are &lt;a href=&quot;https://docs.gradle.org/current/userguide/resolution_strategy_tuning.html&quot;&gt;tools to mitigate this problem&lt;/a&gt;, but the reality is that by just reading the declaration, you&amp;#8217;re not safe.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s even worse than that: what about transitive dependencies?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine that you have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;Foo &amp;#8594; Bar &amp;#8594; Baz&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And that you depend on &lt;code&gt;Foo&lt;/code&gt;. What if a vulnerability is discovered on &lt;code&gt;Baz&lt;/code&gt;? Will you be notified? What kind of automated pull request can such a tool make to make sure that you upgrade &lt;code&gt;Baz&lt;/code&gt;?&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_can_we_do_better&quot; class=&quot;sect0&quot;&gt;Can we do better?&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have some good and bad news for you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The good news is that we can do better.
The bad news is that it&amp;#8217;s not easy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, instead of relying on the declaration, those tools should really rely on the result of dependency resolution.
If, for example, they used the lock files instead of the build files, they would know exactly what a build resolves.
This, however, is only possible if the build uses dependency locking, and only for dependency graphs which are actually locked.
It&amp;#8217;s a reasonable assumption to say that what is locked is the most relevant information, though.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, I said there were bad news.
As soon as you use the resolution result, you almost have to give up on automated remediation (pull requests).
One thing they &lt;em&gt;could&lt;/em&gt; do is patching the lock file.
However, this is in general not a good idea, because, as I explained, lock files are generated: they present to you the result of resolution.
Partially upgrading a lock file, manually, is possible but then you cannot make any guarantee that the app is going to work, because introducing a different dependency version may introduce different transitive dependencies!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;An alternate solution is to gather the information about resolved dependencies during the build: this is what &lt;a href=&quot;https://scans.gradle.com/&quot;&gt;build scans&lt;/a&gt; do for Gradle and Maven, for example.
This information can be extracted during the build and Dependabot would know precisely, reliably, what is resolved by a project.
We even offer a Tooling API to do this kind of work.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then there&amp;#8217;s remediation.
This is the hardest problem.
Because what most people like about Dependabot is actually the automated remediation: pull requests are nice, we all love that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But say, that to fix the transitive dependency issue above, Dependabot suggested to add a first level dependency with a different version.
For Maven, this would work, since it&amp;#8217;s order and depth sensitive.
But it would break your model: the application doesn&amp;#8217;t depend on &lt;code&gt;Baz&lt;/code&gt;: it depends on &lt;code&gt;Foo&lt;/code&gt;, which, by the transitive game, depends on &lt;code&gt;Baz&lt;/code&gt;.
You don&amp;#8217;t want to introduce a first level dependency on &lt;code&gt;Baz&lt;/code&gt; because it doesn&amp;#8217;t make sense.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For Gradle, you could use dependency constraints instead: constraints are meant for this use case.
A &lt;a href=&quot;https://docs.gradle.org/current/userguide/dependency_constraints.html#sec:adding-constraints-transitive-deps&quot;&gt;constraint&lt;/a&gt; adds, as it name implies, a constraint to the equation of the resolution of the graph (a bit like in constraint programming).
They would participate in the dependency graph resolution if, and only if, the dependency they talk about appears in the graph.
In that sense, they don&amp;#8217;t break the application model, by introducing arbitrary first-level dependencies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Our Java ecosystem is polluted by hundreds of accidental first level dependencies and exclusions because of this lack of modeling: it is important to get things right.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, how you declare dependencies matters.
In Gradle, using &lt;a href=&quot;https://docs.gradle.org/current/userguide/rich_versions.html#header&quot;&gt;rich version constraints&lt;/a&gt;, you can explicitly reject bad versions, and you can explain why.&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_conclusion&quot; class=&quot;sect0&quot;&gt;Conclusion&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In conclusion, I think that Dependabot&amp;#8217;s intent is legitimate and that today it&amp;#8217;s better than nothing. Let&amp;#8217;s detect projects using vulnerable dependencies and propose automated remediation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We, as build tool authors, also need to consider the wider context, which is dependency resolution in general, which isn&amp;#8217;t as simple as it seems.
In particular we consider that &lt;em&gt;detection&lt;/em&gt; is an easy problem if you use the right tools, while &lt;em&gt;remediation&lt;/em&gt; is a hard one.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think the current implementation of Dependabot is mostly wrong (at least in the Java ecosystem) as it relies on the declaration. This raises a number of issues:
- it is dependent to the patterns it recognizes
- it assumes that what you see is what you get
- it cannot recognize transitive dependencies actually resolved by your project, so it misses real vulnerabilities
- it doesn&amp;#8217;t matter about the context of use of your dependencies&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The context thing is difficult to solve, but it&amp;#8217;s actually painful because of the noise it creates, in case the &quot;vulnerable dependency&quot; is actually not in your case.
However, I think there are improvements which can me made by actually using the actual resolution results instead.
Then it raises some interesting technical challenges, like how to sandbox execution of builds (GitHub actions already do this) but more importantly how to create an automated pull request from the result of the analysis.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that I also understand that from a Dependabot creator point of view, having to implement build-tool specific logic, like calling the Tooling API, to gather information about resolved dependencies might sound scary.
I still think this is the right thing to do to be correct and, if our goal is really to make the industry safer, that&amp;#8217;s what we should do.
However, we have alternate solutions. For example a few weeks ago I experimented with a &lt;a href=&quot;https://github.com/melix/gradle-command-action/tree/dump-dependencies&quot;&gt;fork of my friend and colleague Paul Merlin&amp;#8217;s Gradle Command GitHub Action&lt;/a&gt; which automatically generates a JSON file of resolved dependencies during the build.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/ysb33r/&quot;&gt;Schalk Cronjé&lt;/a&gt; also mentioned to me the &lt;a href=&quot;https://github.com/jeremylong/dependency-check-gradle&quot;&gt;OWASP plugin&lt;/a&gt;, which I forgot to mention when I originally wrote this blog post, but I think it a great answer and currently better answer because it does exactly what I describe: rely on what you actually resolve, not what you declare, and lets you carefully review the results via a generated report.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m not sure this is the best answer, but it shows that we can attack the problem from different angles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, the key takeaway of this blog post should be: don&amp;#8217;t assume that you are safe because you use Dependabot. You&amp;#8217;re not.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Configuring git to use main instead of master</title>
      <link>https://melix.github.io/blog//2020/06/updating-git.html</link>
      <pubDate>Wed, 17 Jun 2020 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2020/06/updating-git.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don&amp;#8217;t need to explain the backstory, and I am not interested in a discussion whether this change makes sense or not, nor am I interested in the technical problems it could cause if someone changes the name: technical issues shouldn&amp;#8217;t be a reason to stop us from improving.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Actually, if you are reading this, there are good chances you&amp;#8217;re already in the mindset of removing potentially offensive language from your project, thank you!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The fact is, we have better, more descriptive technical names than &quot;master&quot; and &quot;slave&quot; and we don&amp;#8217;t have to use terms which refer to dark ages of our history, so let&amp;#8217;s get rid of them in tech.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, you will learn:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;how to make &lt;code&gt;git init&lt;/code&gt; create your project with a &lt;code&gt;main&lt;/code&gt; branch instead of &lt;code&gt;master&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how to rename your &lt;code&gt;master&lt;/code&gt; branch to &lt;code&gt;main&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how to make the change on GitHub&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Be aware that renaming branches may break your existing integrations (typically with CI or Slack notifications) so only do it when you&amp;#8217;re ready.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_git_init&quot;&gt;Configuring git init&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, when you create a new project, &lt;code&gt;git init&lt;/code&gt; will create a &lt;code&gt;master&lt;/code&gt; branch.
There&amp;#8217;s no option in &lt;code&gt;git init&lt;/code&gt; to change this, but it&amp;#8217;s actually quite easy to set it up differently.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, in your &lt;code&gt;~/.gitconfig&lt;/code&gt; file, add the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;~/.gitconfig&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;[init]
    templateDir = ~/.config/git/template/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then create, if it doesn&amp;#8217;t exist, the following directory:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;mkdir ~/.config/git/template&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;next create this file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;~/.config/git/template/HEAD&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;ref: refs/heads/main&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;(don&amp;#8217;t forget to add a new line at the end of the first line)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Starting from now, calling &lt;code&gt;git init&lt;/code&gt; will create a &lt;code&gt;main&lt;/code&gt; branch instead of &lt;code&gt;master&lt;/code&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s deal with existing projects.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_renaming_your_master_branch&quot;&gt;Renaming your master branch&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For your current projects, you may want to rename the &lt;code&gt;master&lt;/code&gt; branch to &lt;code&gt;main&lt;/code&gt;.
This is also single command in &lt;code&gt;git&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;git checkout master
git branch -m main&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you can push the branch to your remote&amp;#8230;&amp;#8203; but be careful, it will create a &lt;em&gt;new branch&lt;/em&gt; on the remote:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;git push origin main&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_github_to_use_main_instead_of_master&quot;&gt;Configuring GitHub to use &lt;code&gt;main&lt;/code&gt; instead of &lt;code&gt;master&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once you&amp;#8217;ve pushed your new branch, you need to tell GitHub that this is your new &quot;default branch&quot;.
To do this, go to &lt;code&gt;Settings&lt;/code&gt; &amp;#8594; &lt;code&gt;Branches&lt;/code&gt; and select your new branch as the default one:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/github-branch.png&quot; alt=&quot;github branch&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, you need to delete the old branch from GitHub, which can be done by calling this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;git push origin :master&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Done!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Using Java feature previews with Gradle</title>
      <link>https://melix.github.io/blog//2020/06/java-feature-previews-gradle.html</link>
      <pubDate>Thu, 11 Jun 2020 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2020/06/java-feature-previews-gradle.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;This blog post has been updated with the latest Java Toolchain support from Gradle, making it even easier!&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ve probably heard about Java providing features like &lt;a href=&quot;https://blogs.oracle.com/javamagazine/records-come-to-java&quot;&gt;records&lt;/a&gt;, &lt;a href=&quot;https://docs.oracle.com/en/java/javase/13/text_blocks/index.html&quot;&gt;multi-line text blocks&lt;/a&gt; or &lt;a href=&quot;https://blogs.oracle.com/javamagazine/inside-the-language-sealed-types&quot;&gt;sealed types&lt;/a&gt; and you&amp;#8217;d like to try them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those features are called &lt;em&gt;feature previews&lt;/em&gt; and it means a couple of things:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;the Java team wants you to test them and give feedback. They want honest feedback about how it &lt;em&gt;feels&lt;/em&gt; to use them, whether you like them or not. Both ways, feedback is important.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;because they are feature previews, you &lt;em&gt;shouldn&amp;#8217;t&lt;/em&gt; them use in production, but you can play with them for toy projects.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There&amp;#8217;s actually an important thing about point 2 if you are a &lt;em&gt;library author&lt;/em&gt;: &lt;strong&gt;never, ever publish a library which uses feature previews on Maven Central&lt;/strong&gt;. The reason is that the feature previews &lt;em&gt;leak to consumers&lt;/em&gt;: as soon as &lt;em&gt;you&lt;/em&gt; start using them, any project depending on your code will also have to enable them. This is not a problem for toy projects, it&amp;#8217;s clearly a problem for published libraries. In particular, there are no guarantees that the generated bytecode will be compatible with future Java releases, and there are no guarantees that the feature preview will make it to Java eventually.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The goal of this blog post is not to explain what records or sealed classes are, there&amp;#8217;s already a lot of litterature about it.
Instead, we&amp;#8217;re going to explain how to configure your Gradle build to use feature previews and therefore report issues/bugs to the JDK team.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_your_gradle_build&quot;&gt;Configuring your Gradle build&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code in this blog post is available on a &lt;a href=&quot;https://github.com/melix/gradle-java-feature-previews&quot;&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, make sure you are using latest Gradle versions.
If you use the repository above, the Gradle wrapper will make sure that you do.
Gradle 6.5, for example, works perfectly fine with Java 14 and even Java 15.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine that you want to compile the following record:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public record Person(
        String firstName,
        String lastName,
        boolean likeJavaRecords) {

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And execute this test:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;class PersonTest {
    @Test void testRecord() {
        Person cedric = new Person(&quot;Cédric&quot;, &quot;Champeau&quot;, true);
        Person otherCedric = new Person(&quot;Cédric&quot;, &quot;Champeau&quot;, true);
        assertEquals(cedric, otherCedric);
        assertTrue(cedric.likeJavaRecords());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you need to configure the build to do a couple of things:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, we need to tell the Java compiler to use feature previews:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;tasks.withType&amp;lt;JavaCompile&amp;gt;().configureEach {
    options.compilerArgs.add(&quot;--enable-preview&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then we need to tell the test runtime to use feature previews:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;tasks.withType&amp;lt;Test&amp;gt;().configureEach {
    useJUnitPlatform()
    jvmArgs(&quot;--enable-preview&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And that&amp;#8217;s it, you can run the build with &lt;code&gt;./gradlew test&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_gradle_to_use_a_different_jdk_from_its_own_runtime&quot;&gt;Configuring Gradle to use a different JDK from its own runtime&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Usually, people use the same JDK version for running Gradle, than they use to compile and execute tests.
It doesn&amp;#8217;t have to be that way, and actually the Gradle team added support for toolchains to simplify the configuration of builds in this case.
All you need is to tell what JDK to use and Gradle will take care of finding a JDK on your machine which matches the spec, or download it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(15))
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you don&amp;#8217;t have any excuse not to try feature previews!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Mon engagement pour Montaigu-Vendée</title>
      <link>https://melix.github.io/blog//2020/03/mvea2020.html</link>
      <pubDate>Sat, 7 Mar 2020 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2020/03/mvea2020.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai 40 ans et je suis arrivé sur Montaigu voici 17 ans. Comme beaucoup d&amp;#8217;entre nous, c&amp;#8217;est pour des raisons professionnelles que nous y avons emménagé avec ma jeune épouse.
Elle avait trouvé un travail sur Les Herbiers, je travaillais sur Nantes, Montaigu était l&amp;#8217;endroit idéal pour nous.
Nous voici en 2020, nous avons 2 grands garçons, et si notre situation professionnelle a évolué (nous sommes tous 2 télétravailleurs) et que nous aurions pu déménager, nous avons au contraire choisi de faire notre vie ici et sommes attachés à ce territoire.
Il y a 6 ans, nous quittions notre petit logement sur Montaigu et achetions donc notre maison sur Saint Hilaire de Loulay, en village.
Après presque deux décennies passées ici, après nos engagements associatifs, nos nouveaux amis ici, il était temps, enfin, d&amp;#8217;entrer au service des citoyens de Montaigu-Vendée.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/mvea-logo.jpg&quot; alt=&quot;mvea logo&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_liste_montaigu_vendée_ensemble_et_autrement&quot;&gt;La liste Montaigu-Vendée Ensemble et Autrement&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si le territoire de Montaigu-Vendée est riche et, économiquement, le territoire est attractif, il y a beaucoup de choses à améliorer.
J&amp;#8217;ai choisi de m&amp;#8217;engager sur la liste de &lt;a href=&quot;https://mvea2020.fr&quot;&gt;Vincent MATHIEU, Montaigu-Vendée Ensemble et Autremement&lt;/a&gt; parce que je suis convaincu qu&amp;#8217;une autre voie est possible, basée sur 3 piliers qui sont aussi chers à mon coeur:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;la transition écologique, parce que je suis convaincu que c&amp;#8217;est en travaillant au niveau local, en engageant des actions simples à notre niveau que nous feront de ruisseaux de grandes rivières&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;la démocratie participative, où comment remettre le citoyen au coeur des décisions, avoir des élus au service des citoyens et non l&amp;#8217;inverse&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;le mieux vivre ensemble, en prenant en compte &lt;strong&gt;tous&lt;/strong&gt; les habitants, personnes âgées, jeunes, personnes en situation de handicap, de tous milieux sociaux et en exploitant notre très actif réseau associatif&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_transition_ecologique&quot;&gt;La Transition Ecologique&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je suis particulièrement attaché à l&amp;#8217;écologie depuis ma jeunesse.
Lorsque je parle d&amp;#8217;écologie, je prône toujours une écologie pragmatique, pas dogmatique et encore moins ésotérique.
Je suis pour l&amp;#8217;écologie qui fait avancer les choses dans la concertation, une écologie qui prend en compte &lt;strong&gt;tous&lt;/strong&gt; les acteurs, entreprises, paysans, citoyens et enfants.
Le 5 mars dernier, nous étions le &quot;jour du dérèglement&quot;, ce jour de basculement où en France, nous commençons à produire plus de carbone que l&amp;#8217;écosystème peut en absorber.
C&amp;#8217;est dire l&amp;#8217;urgence de la situation, mais l&amp;#8217;écologie ne se limite pas au prisme du réchauffemenent climatique.
En campagne, il est facile de constater les ravages sur la biodiversité: en 40 ans, ce sont 60% des espèces sauvages qui ont disparu, 40 ans seulement!
Comme le citait Antoine de Saint Exupéry, &lt;strong&gt;nous n&amp;#8217;héritons pas de la terres de nos ancêtres, nous empruntons celle de nos enfants&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est ici une différence fondamentale avec la majorité sortante, qui, soyons clairs, n&amp;#8217;a rien fait pour l&amp;#8217;écologie.
Pire, lorsqu&amp;#8217;elle affirme dans les journaux que Vincent MATHIEU &quot;n&amp;#8217;est pas issu du cru local, ses parents n&amp;#8217;ont pas de pieds de vigne dans le secteur&quot;, nous constatons avec effarement un tel mépris de notre génération, des générations futures, mais aussi des 600 nouveaux habitants qui chaque année, arrivent sur notre terroire. 600 habitants, que, au passage, les élus actuels sont heureux de voir participer à l&amp;#8217;activité économique, heureux d&amp;#8217;avoir pour qu&amp;#8217;il soit, come une fois de plus annoncé dans les journaux, nommé Président d&amp;#8217;une Communauté d&amp;#8217;Agglomération qui n&amp;#8217;existe pas encore (faute d&amp;#8217;habitants suffisants !), mais dont il nie l&amp;#8217;expression de la démocratie lorsqu&amp;#8217;ils ne sont pas issus du secteur. Dont acte.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A titre personnel, je suis aussi attaché à la lutte contre la pollution lumineuse.
Je constate, en tant qu&amp;#8217;astronome amateur, la dégradation du ciel nocture.
Je constate que les gens sont surpris lorsqu&amp;#8217;ils découvrent, lors de la manifestation des Etoiles du Lac à La Guyonnière (dont l&amp;#8217;existence est menacée par la majorité en place), qu&amp;#8217;ils peuvent voir la voie lactée.
Je constate aussi que nous n&amp;#8217;avons, même ici en campagne, presque plus de papillons de nuit et que les insectes ont presque tous disparus.
Il s&amp;#8217;agit d&amp;#8217;une catastrophe contre laquelle nous pouvons, tous ensemble, lutter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Que dire de cette majorité, qui, à l&amp;#8217;heure où l&amp;#8217;on parle de planter des arbres, a rasé tous les arbres de la place de la mairie ? Que dire de cette majorité qui a coupé les magnifiques cerisiers en fleurs du Boulevard Auguste Durand pour les remplacer par&amp;#8230;&amp;#8203; du goudron ! Que dire lorsque &lt;strong&gt;tous&lt;/strong&gt; les cours d&amp;#8217;eau du territoire ont leurs indicateurs de qualité dans le rouge ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors peut-on faire mieux ? Avec un tel bilan pour la majorité sortante, ça n&amp;#8217;est pas compliqué.
Je vous invite à lire notre &lt;a href=&quot;https://mvea2020.fr/transition-ecologique.html&quot;&gt;programme sur la transition écologique&lt;/a&gt;.
J&amp;#8217;insisterai sur ces points:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;nous souhaitons aider toutes celles et ceux, entreprises ou particuliers, qui sont prêts à s&amp;#8217;engager dans la transition écologique.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous favoriserons l&amp;#8217;implantation d&amp;#8217;entreprises vertueuses, et aiderons les entreprises existantes pour qu&amp;#8217;elles réalisent des économies d&amp;#8217;énergie (et donc d&amp;#8217;argent !) et réduisent leur impact. Ceci passera par la mise en place d&amp;#8217;indicateurs et de mesure du progrès tout au long du mandat&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous aiderons les habitants de villages dans la mise au normes de l&amp;#8217;assainissmenent. Des solutions écologiques et collectives existent, et aujourd&amp;#8217;hui &lt;em&gt;personne&lt;/em&gt; n&amp;#8217;aide ces habitants dans des choix qui sont souvent extrêmenent onéreux.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous favoriserons l&amp;#8217;accueil de nouveaux paysans bio ou 0-pesticide et développerons l&amp;#8217;alimentation collective par l&amp;#8217;approvisionnement local, tel que celà se fait sur la Guyonnière&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous rendrons l&amp;#8217;accès à la déchetterie plus simple et gratuit. Nous mettrons aussi à disposition des outils pour ceux qui ne peuvent pas facilement se déplacer (broyage, compostage, &amp;#8230;&amp;#8203;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nous développerons et sécuriserons les développements doux (pistes cyclables, chemins piétonniers, &amp;#8230;&amp;#8203;) et mettrons en place des solutions de transport collectif entre les communes déléguées&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_démocratie_participative&quot;&gt;La démocratie participative&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ah, la belle démocratie Montacutaine ! Qui, il y a 6 ans, avait lu qu&amp;#8217;il y aurait fusion des communes dans les programmes ? Qui a été consulté pour cette fusion ? Nous avons bel et bien eu une consultation, celle pour choisir le nom de la commune.
D&amp;#8217;ailleurs, nous, habitants, avions choisi &quot;Montaigu Les Maines&quot;, mais nos élus avaient déja choisi Montaigu-Vendée.
Tout, absolument tout sur Montaigu est à cette image: les élus prennent les décisions dans leur coin, et informent les citoyens a posteriori.
Ceci n&amp;#8217;est pas ma vision de la démocratie.
Même s&amp;#8217;il fallait faire cette fusion, il était nécessaire d&amp;#8217;en informer et de faire une concertation avec les citoyens.
Nous ne sommes pas dupes, à Montaigu, l&amp;#8217;élu est au service du Maire, ses ambitions personnelles annoncées par voie de presse, et non le contraire.
Je ne suis même pas certain qu&amp;#8217;ils se rendent compte de ce qu&amp;#8217;ils font.
Qui, par exemple, a déja vu sur l&amp;#8217;affichage public l&amp;#8217;annonce des conseils municipaux ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous souhaitons remettre le citoyen au coeur des décisions, et celà se fera en mettant en place des structures adaptées, participatives: rganisation de conseils municipaux délégués, composés pour moitié d&amp;#8217;élus et pour l&amp;#8217;autre moitié de citoyens tirés au sort parmi les volontaires. Il ne s&amp;#8217;agit pas, comme le propose l&amp;#8217;autre liste, de choisir nous mêmes les participants, ça n&amp;#8217;est pas notre vision de la démocratie: nous souhaitons une vision non partisane des choses !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Notre territoire est grand et aussi organisé en villages et quartiers. Il nous semble donc indispensable de refléter cet aspect dans les prises de décision, avec l&amp;#8217;organisation de comités locaux, par thématique, afin que les riverains puissent prendre part aux décisions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il est &lt;a href=&quot;https://mvea2020.fr/democratie-participative.html&quot;&gt;temps que le citoyen redevienne le centre de la discussion publique&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_mieux_vivre_ensemble&quot;&gt;Le mieux-vivre ensemble&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il s&amp;#8217;agit encore d&amp;#8217;un point qui me tient particulièrement à coeur.
Notre territoire se doit d&amp;#8217;être accueillant, quelle que soit la population.
Nos élus, par exemple, on fait le choix de payer des amendes plutôt que de respecter l&amp;#8217;obligation de 20% de logements sociaux.
Ils mettent aussi en place des &quot;nouveaux quartiers&quot; tels que les Hauts de Montaigu, où le ticket d&amp;#8217;entrée pour une maison de 110m2 et un terrain de 250m2 se situe aux alentours de 250k€ !
Nous pensons que nous pouvons, que nous &lt;strong&gt;devons&lt;/strong&gt; faire autrement: création d&amp;#8217;éco-quartiers intergénérationnels, par exemple.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ces quartiers ont à la fois un intérêt écologique, mais aussi de relation sociale. Avec une partie de la population qui veillit et une autre partie de la population qui croit rapidement (pour des raisons économiques), nous pensons que nous pouvons organiser nos quartiers de manière à encourager la mixité sociale, la relation entre personnes âgées et jeunes en vivant Ensemble et Autrement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous pensons qu&amp;#8217;il y a une alternative aux EHPAD et qu&amp;#8217;en particulier le maitien des personnes âgées dans un environnement au milieu d&amp;#8217;actifs et de jeunes est à la fois une garantie d&amp;#8217;un veillissement dans de meilleures conditions, mais aussi plus humaine.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous avons aussi la chance, sur notre territoire, d&amp;#8217;avoir un tissu associatif extrêmement actif.
Toutes ces bonnes volontés ont besoin d&amp;#8217;être encouragées.
Il est déja très difficile de trouver des bénévoles, alors que dire lorsque la municipalité ne s&amp;#8217;engage pas ou, pire, tente de saboter des projets parce qu&amp;#8217;ils sont jugés trop &quot;populaires&quot; ?
Nous nous appuierons au contraire sur ces associations et nous mettrons en place la transparence dans l&amp;#8217;attribution des subventions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous transformerons aussi nos mairies annexes en maisons de services aux citoyen, de façon à favoriser l&amp;#8217;interaction, mais aussi aider toutes les personnes en difficulté.
Parfois, il s&amp;#8217;agira de difficultés de logement, économiques, mais aussi parfois des difficultés dans l&amp;#8217;appréhension des outils numériques (nous pensons par exemple à la télé-déclaration de revenus).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous pensons aussi à tous les citoyens, en particulier ceux en situation de handicap.
La situation de la ville de Montaigu est catastrophique à cet égard: impossible pour une personne en fauteuil roulant de faire ses courses en centre-ville.
Nous souhaitons, au contraire, renforcer les centre-villes en les rendant accessibles &lt;strong&gt;pour tous&lt;/strong&gt;, en travaillant avec les petits commerçants qui font vivre nos villes, plutôt qu&amp;#8217;en développant, comme à l&amp;#8217;heure actuelle, les grandes surfaces commerciales en périphérie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Enfin, il s&amp;#8217;agit aussi d&amp;#8217;aider notre jeunesse.
Combien de fois avez-vous croisé des jeunes en train de faire du skate sur la voie publique ? Notre majorité actuelle a préféré offrir une réduction sur le tarif des terrains aux promoteurs immobiliers, plutôt que d&amp;#8217;investir 80k€ (sur un budget de 16M€) pour donner à nos jeunes des lieux où s&amp;#8217;amuser. Que dire de l&amp;#8217;état des pistes cyclables ? Pensez-vous que vos enfants peuvent, en toute sécurité, partir du collège et se rendre à leur entraînement de sport à Saint Georges de Montaigu ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, dans une semaine, le 15 Mars, vous devrez choisir vos élus.
Je me présente humblement sur la liste de Vincent MATHIEU, une liste composée de citoyens impliqués, d&amp;#8217;horizons et compétences différents et j&amp;#8217;espère être bientôt à votre service pour une vie meilleure, Ensemble et Autrement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comme l&amp;#8217;a si bient dit Michel PAVAGEAU, le doyen de notre liste, à Commune Nouvelle, Équipe Nouvelle !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Chronicles of an introvert remote worker</title>
      <link>https://melix.github.io/blog//2020/01/introvert-remote.html</link>
      <pubDate>Fri, 3 Jan 2020 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2020/01/introvert-remote.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This post is the translation in English of the most popular blog post I wrote in October, 2019, which was originally posted in french.
Lots of folks commented they found it useful and that they recognized themselves in the description so I decided to translate it to English.&lt;/p&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The other day I was listening to &lt;a href=&quot;https://lescastcodeurs.com/2019/09/16/lcc-216-l-episode-ou-on-a-perdu-le-compte/&quot;&gt;Les Cast Codeurs podcast&lt;/a&gt; which mentioned the topic of remote working.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some comments made me raise an eyebrow, this post is going to talk about my own experience.
This post is mostly about me and being an introvert.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_remote_working_and_being_an_introvert&quot;&gt;Remote working and being an introvert&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;ve been &lt;em&gt;almost&lt;/em&gt; full-time remote worker for almost 10 years.
I&amp;#8217;m saying &lt;em&gt;almost&lt;/em&gt; because in practice, I&amp;#8217;m moving from time to time for profesional reasons (conferences, meetings).
However, for my daily job, everything is done from home.
Before being a remote worker, I was driving a lot: my job was in Nantes, around 45km from home.
That was about ~90km a day, but more importantly between 2 and 3 hours of commute a day.
The day I switched jobs, working for VMware on the Groovy language, the first shock was that I was recovering those 2 to 3 hours a day.
That&amp;#8217;s a lot of time to spend with your kids (dropping them at school, driving them to sports, &amp;#8230;&amp;#8203;) or doing housekeeping (fixing, gardening, sports, &amp;#8230;&amp;#8203;).
I won&amp;#8217;t come back to those advantages because they are mostly known, the only real drawback to me is being capable of handling your own work hours, that is to say, contrary to the belief, not working &lt;em&gt;too much&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The thing I want to talk about is this comment from Antonio Goncalvés who said:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dump your coffee maker, go out, see people, it&amp;#8217;s important to see other human beings!&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This &lt;a href=&quot;https://twitter.com/CedricChampeau/status/1173893698997936130&quot;&gt;made me react&lt;/a&gt; so I wanted to come back to this topic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, this advice only works if you live in a city, which is not my case.
I (intentionally) live in the countryside, 5kms from the town center.
A &quot;small coffee break&quot; turns into an expedition in those conditions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But let&amp;#8217;s come to the core of the topic: &quot;It&amp;#8217;s important to see and talk to human beings&quot;, which relates to the &lt;em&gt;necessity not to be alone&lt;/em&gt;.
This is a topic I care about and resonates with a question I often answered when I&amp;#8217;m talking about remote work:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But aren&amp;#8217;t you tired of being alone and not seeing anybody?&quot;&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Honest answer: &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I understand people who need this, but &lt;strong&gt;don&amp;#8217;t think everybody works like you&lt;/strong&gt; and &lt;em&gt;need&lt;/em&gt; to see other people.
Some folks like me live perfectly well without seeing anybody.
I can spend days alone, without me going mad or missing any social relationship.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;m part of this population called the &lt;em&gt;introverts&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;An &lt;em&gt;introvert&lt;/em&gt;, contrary to the popular belief, isn&amp;#8217;t antisocial, selfish or without any kind of empathy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An &lt;em&gt;introvert&lt;/em&gt; is someone whose energy is drained by the crowd, by social relationships. It&amp;#8217;s the opposite of an &lt;em&gt;extravert&lt;/em&gt; who needs to see people to recover energy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An &lt;em&gt;introvert&lt;/em&gt; is someone who can&amp;#8217;t stand smalltalk, because they don&amp;#8217;t bring anything to him/her except from draining their energy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An &lt;em&gt;introver&lt;/em&gt; is someone who can talk hours on a topic (s)he&amp;#8217;s passionate about because it&amp;#8217;s &lt;em&gt;worth their energy&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I was a kid I already avoided being in a group of people.
I didn&amp;#8217;t have many friends (but the friends I had back then I still have them today).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I always freaked out at the idea of being in a group where I knew nobody, be it at school, at sport or even family parties.
Even if I &lt;em&gt;knew&lt;/em&gt; someone, being &lt;em&gt;in a group&lt;/em&gt;, having to entertain social relationships was of extreme difficulty (and it still is today, to some extent).
Everything I cared as a child about back then was being &quot;excellent&quot; at school and my parents be proud of me.
This caused me to get some nicknames (&quot;the nerd&quot;), being hassled or even get some not so nice words written on the back of my classroom photographs, for a large part of my childhood.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an example, I always refused to go to summer camps (the only experience I got, a week in a stud farm, was so painful to me I still remember it).
I also refused going to snow camps.
However, I &lt;em&gt;did&lt;/em&gt; accept going to England, Ireland and Spain with school, not without fighting myself, because I knew I could learn something out of it, but also because I knew I would be in a small group with a friend.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly, having to stand in front of the rest of the classroom to recite a poem, or worse, sing, was pure torture to me.
On the contrary, I loved being at the University of Science in Nantes, where I could spend some time with 2 or 3 friends max at the coffee shop, discussing with them.
I didn&amp;#8217;t like much the software engineering school I joined to after that, where I had to be extremely creative to avoid the student integration parties, after-work parties and all those driking games most students were fond of: it was incredibly difficult to be recognized as a person without being excluded because I didn&amp;#8217;t participate in those events.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s talk about those &quot;integration&quot; parties. What&amp;#8217;s fun for some, being drunk, &quot;gently&quot; humiliating others, was just disgust and fear for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that I think about it, few people know it, but I spent my whole scolarity in Nantes, not because everything was available there (it was, really), but because I was petrified at the idea of beling &quot;alone&quot; in a new University, an engineering school, somewhere else at the other end of France, &amp;#8230;&amp;#8203;
I remember a teacher who blamed me for not going in a well known French school despite I had the &quot;capacity&quot; do it.
In retrospect I don&amp;#8217;t think it was a big mistake, I&amp;#8217;m quite happy where I am today!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_i_would_never_hire_someone_like_you&quot;&gt;I would never hire someone like you!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Everything I explained may sound surprising from someone who, today, gives talks at conferences, sometimes in front of hundreds of people, which sounds a bit irrealistic.
So what&amp;#8217;s the difference?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well the difference is that when I talk to you in a such a context, I &lt;strong&gt;understand the topic&lt;/strong&gt; (or at least I think I understand it ;)).
I can talk to you openly because I know the questions I will get are directly related to the topic I&amp;#8217;m talking about.
There&amp;#8217;s almost no room for the &lt;em&gt;unknown&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s also for this reason that it&amp;#8217;s still very difficult to me, even today, to reach out to others.
I am still completely incapable of doing small talk.
This goes even beyond that: I&amp;#8217;ve traveled abroad a number of times, multiple times in the US for example, but I &lt;em&gt;never&lt;/em&gt; went outside alone to visit (at best I can walk an hour or two in the neighorhood).
That&amp;#8217;s because doing this drives me outside of my comfort zone: having to talk to people I don&amp;#8217;t know, ordering a meal, asking for directions: all this is draining my energy. It&amp;#8217;s always easy to say you should go out of your comfort zone when doing this is not a trial for you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, if I know one or two people and that they kindly ask me to join them, in most cases it will be fine and I would appreciate visiting!
Everybody&amp;#8217;s telling me I&amp;#8217;m incredibly lucky to travel.
Well, maybe, but I, for one, hate this, at least I hate it if I have to do this without my family&amp;#8230;&amp;#8203;
Even going to Paris, realizing how many people live there, feeling like an ant in the anthill, remind me how much I hate this!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, I avoid as much as I can &quot;parties&quot; like speaker dinners or corporate events.
They are often described as the &lt;em&gt;must do&lt;/em&gt; of networking.
While it&amp;#8217;s true that you can learn a lot in those events, they are also incredibly stressful to me.
When I join them, most of the time I&amp;#8217;m trying to identify someone I know, stick with them but I would often leave early and I have to go to my hotel room alone to recover.
I wouldn&amp;#8217;t necessarily &lt;em&gt;sleep&lt;/em&gt;, as some people think I do: often I would work late in my hotel room, I just need to be &lt;em&gt;alone&lt;/em&gt;.
The most terrifying thing to me in those parties is when conversations become &lt;em&gt;extra-professional&lt;/em&gt; which is something I have no &quot;skill&quot; for.
Some would say I&amp;#8217;m a boring guy, that there&amp;#8217;s no interest in talking to me and that&amp;#8217;s probably right if you&amp;#8217;re looking for someone with an extraordinary life, mine is not that much :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A natural conclusion that some people draw from this is that of course I can&amp;#8217;t be a good team player.
In fact I think that&amp;#8217;s quite the opposite: I value &lt;em&gt;trust&lt;/em&gt; like no one else and I think you can &lt;em&gt;trust&lt;/em&gt; me.
One shouldn&amp;#8217;t mix my incapacity to have simple inter-personal relationships with my capacity to have useful professional interactions, which is another totally different dimension.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As I explained, I&amp;#8217;m regularly giving talks and I love more than anything else sharing knowledge and information, helping others.
I also enjoy working with people more competent than me so that I can continue to learn and make progress: in this context working in a team is extremely effective.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Also, it&amp;#8217;s not because you&amp;#8217;re working remotely that you don&amp;#8217;t see anyone and that, effectively, you work &lt;em&gt;alone&lt;/em&gt;.
It&amp;#8217;s quite the opposite: we work as a team.
As other teams we do daily standups (via hangouts or Slack), we organize work.
Sometimes we even do face to face meetings or leverage conferences to meet together and do some work.
So it&amp;#8217;s not because you&amp;#8217;re an introvert that it&amp;#8217;s a problem: I think my colleagues would tell you that it works pretty well actually.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In short, don&amp;#8217;t be afraid of this aspect: being alone is not a problem for everyone. Maybe it is for you, but definitely not for everyone.
On the opposite, being alone can also boost productivity: no interruption, no useless meetings, ability to focus on a problem for hours etc&amp;#8230;&amp;#8203;
Being introvert doesn&amp;#8217;t mean either that someone is not capable of working in a team: it doesn&amp;#8217;t prevent &lt;em&gt;at all&lt;/em&gt; from helping others, colleagues or customers.
On the contrary, the professional relationship is focused.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So how does it work in practice?
At Gradle, almost everybody is working remotely.
For the socializing aspect, we have an &lt;em&gt;optional&lt;/em&gt; weekly meeting, called &quot;coffee time&quot;, that anyone willing to can join and chat about extra-work topics.
Some need this, I don&amp;#8217;t: the good thing is that we recognize not everybody&amp;#8217;s the same.
Actually I would be in difficulty to join this meeting and know &lt;em&gt;what&lt;/em&gt; to talk about.
Sometimes I even try to avoid being the first one joining a remote call to avoid having to do some small talk because I&amp;#8217;m so uncomfortable with this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, again, talk to me about a topic I know about or that I&amp;#8217;m passionate about. Ask me about a problem to solve, ask me about helping others and I&amp;#8217;ll be happy to do so because there&amp;#8217;s no room for the unknown.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly if we meet in person at a conference and that you wish to talk to me, go ahead: it&amp;#8217;s very likely I will enjoy our conversation: I had several times the opportunity to talk to very famous folks of the Java community (James Gosling, Brian Goetz, Mark Reinholds, &amp;#8230;&amp;#8203;) and so many others but I just &lt;em&gt;couldn&amp;#8217;t&lt;/em&gt;, it was, physically, impossible to me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In fact I have so much difficulties coming to someone and opening a discussion that if you do the first step it&amp;#8217;s &lt;em&gt;much&lt;/em&gt; easier.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So: don&amp;#8217;t be surprised if I walk the area 3 times in a row without asking for directions. Don&amp;#8217;t be surprised if I don&amp;#8217;t phone or text you. I&amp;#8217;m not ignoring you.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_dont_be_ashamed_of_being_an_introvert_but_make_others_understand_what_it_means&quot;&gt;Don&amp;#8217;t be ashamed of being an introvert but make others understand what it means&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last, in a &lt;a href=&quot;https://twitter.com/CedricChampeau/status/1173893698997936130&quot;&gt;Tweet&lt;/a&gt; I was saying that I was &quot;healing myself&quot;.
That&amp;#8217;s both true and false at the same time.
It&amp;#8217;s true because I&amp;#8217;m aware of the importance of the ignorance of a lot of people about this condition of mine, so I try to work, for example, speaking with others in different contexts.
I am for example the secretary of my karate club, which forces me to talk to people I don&amp;#8217;t know.
I am also the coach of my younger boy&amp;#8217;s (10 yo) basketball team, which I enjoy very much doing: it&amp;#8217;s an activity which allows both spending time with my kid, requires some public communication skills and is very gratifying (seeing kids happy to play, win a match, share this with their parents etc&amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least it&amp;#8217;s also a message for my son who I know feels very much like me: he also has difficulties speaking to others and I know he works hard to get accepted. He&amp;#8217;s also so proud when he gets recognition from his community.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It took me years to put a name on what I am: I&amp;#8217;m an &lt;em&gt;introvert&lt;/em&gt; and often I have to fight myself not to be ashamed of this.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle myth busting: scripting</title>
      <link>https://melix.github.io/blog//2019/11/gradle-scripting.html</link>
      <pubDate>Sun, 3 Nov 2019 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2019/11/gradle-scripting.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don&amp;#8217;t particularly enjoy Twitter as a medium for debating (no surprise my bio mentions &quot;this is not a support channel&quot;).
This happened again this week, I got caught in a Maven vs Gradle debate, one more, after I replied to &lt;a href=&quot;https://twitter.com/lukaseder/status/1189889509254713344&quot;&gt;Lukas Eder&lt;/a&gt; that his tweet was a call for FUD.
And it did happen: no surprise, when you submit something like that, the only answers you&amp;#8217;ll get are either people going in your direction &quot;oh yeah, Gradle sucks and here is my personal experience&quot; or similar, this is just human nature.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_good_old_debate&quot;&gt;The good old debate&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, most of the answers cycle around the same, good old, debate: Gradle uses scripting (Groovy or Kotlin) vs Maven uses declarative.
You&amp;#8217;ll aways find people telling you that XML is better because it locks you down, its fully declarative (&lt;a href=&quot;https://maven.apache.org/plugins/maven-antrun-plugin/&quot;&gt;is it&lt;/a&gt;, really?) and everybody is forced to do the same.
I don&amp;#8217;t counter those arguments, this is a strength of Maven, but it also comes with a number of drawbacks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I promised some of the folks in the conversation some answers (please look down for direct answers to tweets), so here they are. I&amp;#8217;m answering on a blog post because again Twitter is not good for this, it&amp;#8217;s causing a lot of misunderstandings, because you get into multiple, parallel conversations with different people who accidentally get mentioned, and get scuds fired at you without even having time to answer&amp;#8230;&amp;#8203; Even a blog post is not enough, there&amp;#8217;s so much to say on this topic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, on the so called &quot;declarative vs imperative&quot; model, I will always disagree on this dichotomy. I disagree that Gradle isn&amp;#8217;t declarative. It&amp;#8217;s as declarative as you want it to be. Take this build file I wrote recently, which is an &lt;em&gt;Asciidoctor Reveal.js presentation template&lt;/em&gt; (it allows writing slide decks with Asciidoctor and reveal.js). Here&amp;#8217;s what my build file looks like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;kotlin&quot;&gt;plugins {
    id(&quot;org.gradle.presentation.asciidoctor&quot;)
}

presentation {
    githubUserName.set(&quot;melix&quot;)
}

dependencies {
    asciidoctor(&quot;org.asciidoctor:asciidoctorj-diagram:1.5.11&quot;)
}

tasks {
    asciidoctor {
        requires(&quot;asciidoctor-diagram&quot;)
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I wouldn&amp;#8217;t particularly say this is imperative. It looks &lt;em&gt;very declarative&lt;/em&gt; to me. Concise too. The fact it uses an &lt;em&gt;imperative language&lt;/em&gt; is orthogonal, but it does, however, create the ability to write imperative code in the build.
Note, however, that a dependency was declared for &lt;em&gt;asciidoctor&lt;/em&gt;. This is a major, and probably the most important, difference with Maven: &lt;em&gt;compile&lt;/em&gt; or &lt;em&gt;runtime&lt;/em&gt; doesn&amp;#8217;t make sense here. We declare a dependency for &lt;em&gt;asciidoctor rendering&lt;/em&gt;. There&amp;#8217;s no Java library being built here, it&amp;#8217;s a presentation. Gradle lets you model precisely &lt;em&gt;what you build&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, in the end, I think what matters is not &lt;em&gt;declarative&lt;/em&gt; vs &lt;em&gt;scripting&lt;/em&gt;. I think what people really want is to reduce the risks of writing bad things. Locking down using XML is &lt;em&gt;one&lt;/em&gt; way to achieve this, but it&amp;#8217;s not the only one. For example, Gradle build scripts &lt;a href=&quot;https://github.com/nebula-plugins/gradle-lint-plugin&quot;&gt;may be linted&lt;/a&gt;. In other words, you can apply on a Gradle build the same tooling you are used to work with when dealing with your own code: checkstyle, findbugs, &amp;#8230;&amp;#8203; You don&amp;#8217;t &lt;em&gt;have to&lt;/em&gt;, but you can.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The consequence is that yes, there are many different ways you can layout your build with Gradle. This is not different from how you can layout your code in a project: we don&amp;#8217;t tell you in which package you should put your beans, services, &amp;#8230;&amp;#8203; However, there&amp;#8217;s a big misconception that I&amp;#8217;d like to fight:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, for a Java project, Gradle follows the same conventions as Maven.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s as simple as that. Sources will be in &lt;code&gt;src/main/java&lt;/code&gt;. Tests will be in &lt;code&gt;src/test/java&lt;/code&gt;. Gradle gives you the freedom to diverge from this convention, but this is &lt;em&gt;not&lt;/em&gt; encouraged, and to be honest, I&amp;#8217;ve almost never seen any build diverging from those conventions. On rare occasions, those were actually builds migrated from &lt;em&gt;other&lt;/em&gt; build systems (in particular Ant) where at the time there wasn&amp;#8217;t any convention. Gradle offers the flexibility to reuse an existing layout without much hassle.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gradle_is_too_flexible&quot;&gt;Gradle is too flexible?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All in all, the argument that &quot;Gradle is too flexible&quot; is a fallacy.
It&amp;#8217;s all about good engineering practices, putting the right tools in place, and this is nothing different from any engineering work we do everyday.
If you can do it for your code, you can do it for your build.
The interesting thing is &lt;em&gt;why you think you shouldn&amp;#8217;t have the same quality expectation levels for your build as you have for your code&lt;/em&gt;.
Often the answer is just &quot;I don&amp;#8217;t care much about the build, I&amp;#8217;m writing code, this is what I&amp;#8217;m paid for&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And this is where the discussion becomes interesting, because I think this is a bias that lots of developers have.
They don&amp;#8217;t even realize how much time they are losing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Tell me, how likely is it that you change your build scripts, compared to the number of times you&amp;#8217;re effectively going to run &lt;code&gt;mvn clean install&lt;/code&gt; or &lt;code&gt;gradle test&lt;/code&gt;?
The reality is that you&amp;#8217;re &lt;em&gt;running the build&lt;/em&gt; much more often that you change it.
Therefore, &lt;em&gt;correctness&lt;/em&gt;, incremental builds, incremental compilation, compile avoidance, task output caching, are far more important to developer productivity than the declarativeness aspect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sure pure declarativeness is a good thing and this is why I encourage Gradle users to write nice, synthetic build files, but this is &lt;em&gt;not&lt;/em&gt; the most important aspect for &lt;a href=&quot;https://gradle.com/developer-productivity-engineering/&quot;&gt;developer productivity&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My point is therefore that if you only focus on the &lt;em&gt;surface&lt;/em&gt;, that is to say the language used to express the build (XML vs Groovy/Kotlin), then you&amp;#8217;re missing the most important part to me, which is the underlying Gradle model, far more advanced than what you have in other tools. The Gradle API surfaces this model and has a number of advantages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A &lt;em&gt;task&lt;/em&gt; can be seen as a &lt;em&gt;function&lt;/em&gt;. It &lt;em&gt;declares&lt;/em&gt; inputs and outputs. For the same inputs, the output are always the same: this provides up-to-date checking and cache-ability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A task inputs can be another task outputs. This provides &lt;em&gt;implicit dependencies&lt;/em&gt;: Gradle knows that if you want to run &quot;test&quot;, you have to compile first, but it also knows that whatever else is an input to the tests need to be executed.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a consequence, I already wrote about why &lt;a href=&quot;https://melix.github.io/blog/2018/09/gradle-lifecycle.html&quot;&gt;it&amp;#8217;s wrong to think that Gradle doesn&amp;#8217;t have lifecycle tasks&lt;/a&gt;. In fact, Gradle has them, but is also &lt;em&gt;significantly more precise&lt;/em&gt;. The &quot;phase&quot; approach of Maven is way to coarse: it&amp;#8217;s doomed to execute too much, prevents smart parallelism, and leads to dirty workarounds (&lt;code&gt;-x &amp;#8230;&amp;#8203;.&lt;/code&gt; on the CLI to avoid things you know are not necessary).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly, say you want to test your application on different JDKs and have a single build execute tests for all target JVMs, which is different from the JVM which runs the build tool. With a scripting approach like Gradle, this is totally doable. I won&amp;#8217;t say easy because we can definitely do better to make this use case better, but the underlying model makes it quite simple. You don&amp;#8217;t want to &lt;em&gt;rebuild&lt;/em&gt; your application for each target VM. All you want is to &lt;em&gt;test&lt;/em&gt; on different platforms, and therefore the only step should be a different target VM for test execution. Tools like Maven force you into arbitrary things like defining Maven profiles, and force you into rebuilding everything. This is a giant waste of time for something you don&amp;#8217;t need!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a different topic, this is no surprise that Gradle can build for different ecosystems: Java, Scala, C++, Kotlin, Kotlin Native, Python, &amp;#8230;&amp;#8203; The underlying infrastructure makes it possible. Even for a single ecosystem, Gradle can declare what the difference between a &lt;a href=&quot;https://docs.gradle.org/6.0-rc-2/userguide/java_library_plugin.html&quot;&gt;Java Library&lt;/a&gt;, a &lt;a href=&quot;https://docs.gradle.org/6.0-rc-2/userguide/java_platform_plugin.html&quot;&gt;Java Platform&lt;/a&gt; or an &lt;a href=&quot;https://docs.gradle.org/6.0-rc-2/userguide/application_plugin.html&quot;&gt;application&lt;/a&gt; is.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I could talk hours about why it&amp;#8217;s important to model properly software, and actually with the release of Gradle 6 we&amp;#8217;ll have a series of blog posts explaining why we think it&amp;#8217;s a game changer in terms of dependency management. If you&amp;#8217;re tired of having to fix the same &quot;multiple slf4j bindings&quot; in each and every project, tired of Guava being upgraded from &lt;code&gt;jre&lt;/code&gt; to &lt;code&gt;android&lt;/code&gt;, frustrated by incompatibilities of Scala 2.11 and 2.12 dependencies, tired of not knowing which of those Maven optional dependencies is important for you to add, you&amp;#8217;ll understand what I mean.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_direct_answer_to_some_tweets&quot;&gt;Direct answer to some tweets&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;ll try to answer more direct questions in this section. Sorry if I missed yours, I got quite a few comments/answers&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I would sacrifice caches, dependency locks and better plugins to version to have a declarative build process instead of an imperative one. Give me a declarative Gradle and I will love it.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again, I think this is the wrong tradeoff. Given that you run the build way more often that you change it, declarativeness (that you &lt;em&gt;can&lt;/em&gt; have with Gradle) shouldn&amp;#8217;t be the goal. Your goal should be to reduce your build times, make your build reproducible, improve your developer productivity. Declarativeness is &lt;em&gt;not a goal&lt;/em&gt;, it&amp;#8217;s at best a &lt;em&gt;mean&lt;/em&gt;, but not sufficient by itself. A declarative Gradle, whatever that means, would help you reduce the cognitive overhead, but wouldn&amp;#8217;t help you better model what your application needs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;make a one liner the ability to publish on different repos the snapshot and release artifacts. The way it was done on Gradle 4.x was broken on 5.x and the only way we found to do it is a horrible hack&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here&amp;#8217;s a &lt;a href=&quot;https://gradle.com/blog/dependency-management-with-gradle-part-3-publishing-and-release-strategies/&quot;&gt;webinar about publishing&lt;/a&gt;. Publishing is not complicated with Gradle. It used to be poorly documented, and the old publishing plugins didn&amp;#8217;t help. But publishing to a snapshot repository should be trivial already.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some people will prefer to do their own way, some people will prefer to have a less expressive tool that will produce similar build processes on their projects. Gradle give you the former, Maven the latter. As I say, a matter of taste.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A less expressive tool reduces the risks of writing &lt;em&gt;bad builds&lt;/em&gt;. It doesn&amp;#8217;t help, however, in developing correct, reproducible, fast builds. An, again, I disagree that Gradle leads to &quot;custom builds&quot; everywhere. Most people stick to the defaults and are very happy with them. The more complex builds you find in the wild are those which have indeed very specific needs, or need to be tweaked for performance, producing more artifacts, combinations of artifacts or testing. Things that you can&amp;#8217;t easily do with Maven profiles, for example, because profiles are &lt;em&gt;adhoc&lt;/em&gt; solutions which do not combine well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle tries to create a fake sense of declarativeness, but it is just an illusion.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s not an illusion. Gradle has a clear separation between its configuration model and execution model. All tasks have declared inputs. The plugins create either new tasks or &lt;em&gt;conventions&lt;/em&gt;. This is not an illusion, this is the reality. Now, because you &lt;em&gt;can&lt;/em&gt; write &lt;code&gt;if&lt;/code&gt; or loops doesn&amp;#8217;t mean it&amp;#8217;s not declarative, it&amp;#8217;s imperative-declarativeness. And yes, you can end up with giant build scripts with &quot;code&quot; inside. If you have, do yourself a favor, &lt;em&gt;refactor&lt;/em&gt; your build like you would with your code, because no one should tolerate this. Use &lt;code&gt;buildSrc&lt;/code&gt;, this is your friend.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think library dependencies is not correctly supported by IDEs and Java modules are better.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s not correct. We&amp;#8217;ve been using the native Gradle IntelliJ support for years at Gradle, with &lt;em&gt;api&lt;/em&gt; and &lt;em&gt;implementation&lt;/em&gt; separation, and it works exactly like it should. Implementation dependencies are hidden from consumers, like they should. If you don&amp;#8217;t see this, either you didn&amp;#8217;t declare the dependencies or you have a bug in the IDE, in which case it needs to be reported.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even worst, Gradle don&amp;#8217;t have an official plugin to deal with module-info. there was an old post that says it is not necessay with Gradle because lib dependencies were better (they don&amp;#8217;t)&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don&amp;#8217;t think anyone said you don&amp;#8217;t need &lt;code&gt;module-info&lt;/code&gt;. There are different things in play:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;separation of API and implementation: Gradle supports this, and it maps to &lt;code&gt;requires&lt;/code&gt; vs &lt;code&gt;requires transitive&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;declaration of public API packages: Gradle &lt;em&gt;used to have&lt;/em&gt; this with the deprecated &quot;software model&quot;. It still has to be backported to the current configuration model. For this, &lt;code&gt;module-info&lt;/code&gt; works fine but it forces you into using the &quot;modular world&quot;, which a lot of libraries, frameworks and IDEs are not ready for.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;declaration of services: Gradle doesn&amp;#8217;t support this.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can you use modules with Gradle? Yes, there&amp;#8217;s a quite good &lt;a href=&quot;https://github.com/java9-modularity/gradle-modules-plugin&quot;&gt;plugin&lt;/a&gt; to do it. We are planning to support modules and modularity in general better in Gradle, but not short term, because we have bigger pain to solve for our users first. It doesn&amp;#8217;t mean we don&amp;#8217;t consider this important.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don&amp;#8217;t get why Gradle allow you to explain what your app is better than Maven. In fact I think it is more difficult to explain it on a script that descriptivelly.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; the question is what Gradle models better than Maven. A good example here is &lt;code&gt;api&lt;/code&gt; vs &lt;code&gt;implementation&lt;/code&gt; dependencies. Because Maven uses the &lt;em&gt;same descriptor (pom.xml)&lt;/em&gt; for the producer and the consumer, a dependency declared in the &lt;code&gt;&amp;lt;compile&amp;gt;&lt;/code&gt; scope ends up on the compile classpath of the consumers. This is &lt;em&gt;leaking internal implementation details&lt;/em&gt; to consumers, which is very bad because it makes it very hard to evolve libraries, because changing an internal dependency would break consumers which accidentally started depending on your own transitives. This is &lt;em&gt;just&lt;/em&gt; an example of course, there are many other differences (like, why we consider that &lt;code&gt;exclude&lt;/code&gt; is a bad workaround in general, more on this topic in Gradle 6, if you want to read &lt;a href=&quot;https://docs.gradle.org/current/userguide/introduction_dependency_management.html&quot;&gt;our docs&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The builds I’ve seen have been very spaghettish and clearly copy-and-pasted together un-understood recipes from SO.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes, there are bad builds out there. With Gradle it&amp;#8217;s frequent for quite old builds from early adopters. More recent builds tend to be much cleaner, because we made a significant effort in guides, getting started samples, documentation. You&amp;#8217;ll always find bad things, and it should be encouraged to fix. On this topic, tools like &lt;a href=&quot;https://scans.gradle.com&quot;&gt;build scans&lt;/a&gt; really help. And copy/pasting from SO is indeed a bad thing. If you copy and paste without understanding what it does, well, bad things can happen&amp;#8230;&amp;#8203; That said I&amp;#8217;ve seen very scary Maven builds too, and believe me or not, some of our customers wouldn&amp;#8217;t be proud to show you their Maven builds. It&amp;#8217;s the &quot;personal experience fallacy&quot;. I&amp;#8217;ve experienced very clean Gradle builds, you&amp;#8217;ve experienced very bad Gradle builds. I&amp;#8217;ve also written bad Gradle builds, which I dramatically improved, making them more correct, faster, &amp;#8230;&amp;#8203; Gradle is like any other technology: learn it and you can understand what it brings.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle performance/caching are very attractive but the scripting possibility is a deal breaker. A « declarative-only » Gradle would be perfect for people like me.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again I think &quot;declarative&quot; is the wrong term here. Locked down to reduce the risks of doing bad things is what you want. It doesn&amp;#8217;t matter if it&amp;#8217;s Kotlin, Groovy, XML or whatever else. It doesn&amp;#8217;t matter if you can use &lt;code&gt;if&lt;/code&gt; or &lt;code&gt;for&lt;/code&gt; loops. What matters is &lt;em&gt;what you can express&lt;/em&gt;, and &lt;em&gt;what should be limited&lt;/em&gt;. It&amp;#8217;s all good engineering that we must share within the industry, find the best patterns, discourage the bad ones. There are quite a few things in the Android world (which uses Gradle) in this direction. We, at Gradle, should do more, but it&amp;#8217;s always a matter of priorities: fixing the most important user pain first. By the way, we provide a Maven build cache with Gradle Enterprise. That is to say, the ability to cache Maven builds using Gradle Enterprise. However, this is limited to &quot;clean builds&quot; (which Maven users are used to do in any case), because of the limitations of the Maven execution model (no knowledge of what each plugin or mojo does, where it writes files, &amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;IMHO the biggest feature of Gradle that Maven doesn&amp;#8217;t have is the ability to change the version of the project&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, this is just an accidental example of the interest of having access to the API in a build script. It offers a number of options for the release process, but that&amp;#8217;s not the only one.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My only complain about @gradle is how it is unnecessarily complex to deploy a multi-module project to central. Too much copy &amp;amp; paste, or you need to make an init script, which I still haven&amp;#8217;t managed to do.&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Technically the problem is not &quot;how to deploy a multi-module project to Central&quot;, but rather, how do I avoid duplicating configuration between scripts. This is what &lt;code&gt;buildSrc&lt;/code&gt; is for. As soon as you have repetition, then, it means a plugin makes sense. &lt;code&gt;buildSrc&lt;/code&gt; can be seen as &quot;local plugins&quot;, and this is where you should write your common code. Then each project applies a plugin to publish. This is a &lt;em&gt;composition&lt;/em&gt; model, as opposed to the &lt;em&gt;inheritance&lt;/em&gt; model of Maven.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I like all those (caching, incrementality, &amp;#8230;&amp;#8203;) , in theory, but for my needs they are more complexity than feature&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don&amp;#8217;t think those are complexity. A task declares its inputs. If you do, you benefit from up-to-date checking, and with a bit more configuration, caching. You don&amp;#8217;t &lt;em&gt;have to&lt;/em&gt;. If you don&amp;#8217;t declare the inputs/outputs, you&amp;#8217;re back to the &quot;Maven&quot; approach where the build tools knows nothing about what a task does, at the difference that Gradle knows that it knows nothing, so can be a bit smarter. As soon as you start declaring your inputs, you benefit from more. It&amp;#8217;s more work, for sure, but it&amp;#8217;s not that complex and the benefit is huge.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Chroniques d&amp;#8217;un introverti en télétravail</title>
      <link>https://melix.github.io/blog//2019/09/introverti-teletravail.html</link>
      <pubDate>Sun, 29 Sep 2019 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2019/09/introverti-teletravail.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;autre jour j&amp;#8217;écoutais le podcast &lt;a href=&quot;https://lescastcodeurs.com/2019/09/16/lcc-216-l-episode-ou-on-a-perdu-le-compte/&quot;&gt;Les Cast Codeurs&lt;/a&gt; qui abordait le sujet du télétravail.
Quelques remarques m&amp;#8217;ont fait tiquer, je m&amp;#8217;en vais donc ici vous raconter mon expérience, mais surtout vous parler de moi et de l&amp;#8217;introversion.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_télétravail_et_lintroversion&quot;&gt;Le télétravail et l&amp;#8217;introversion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Voici maintenant presque 10 ans que je suis presque à 100% en télétravail. Je dis presque, parce qu&amp;#8217;en pratique, j&amp;#8217;ai quelques déplacements professionnels (conférences, meetings) de temps en temps, mais pour mon boulot de tous les jours, c&amp;#8217;est tout à la maison.
Avant de faire du télétravail, je roulais beaucoup: mon emploi était sur Nantes, à 45km de chez moi. Ca faisait donc 90km par jour, mais surtout entre 2 et 3h de transport par jour (eh oui, j&amp;#8217;avais la chance de devoir traverser le pont de Cheviré, pour ceux qui connaissent&amp;#8230;&amp;#8203;).
Bref, le jour où j&amp;#8217;ai changé d&amp;#8217;emploi, pour passer chez VMware pour travailler sur le langage Groovy, le premier choc pour moi ça a été de récupérer ces 2 ou 3 heures par jour.
C&amp;#8217;est autant de temps qu&amp;#8217;on peut passer à s&amp;#8217;occuper de ses enfants (les déposer à l&amp;#8217;école, les emmener au sport, &amp;#8230;&amp;#8203;) ou à faire des activités à la maison (jardinage, sport, &amp;#8230;&amp;#8203;).
Je ne reviendrais pas sur ces aspects, parce qu&amp;#8217;ils sont largement connus, le seul &quot;inconvénient&quot; pour moi étant surtout d&amp;#8217;être capable de maîtriser ses horaires, c&amp;#8217;est à dire de ne pas, contrairement à ce qu&amp;#8217;on pense, faire &lt;em&gt;trop&lt;/em&gt; d&amp;#8217;heures !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Non, ce sur quoi je veux revenir, c&amp;#8217;est cette remarque d&amp;#8217;Antonio Goncalvés, qui, en conseil, dit en substance:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&quot;Balancez votre cafetière, sortez dans les bars, voyez des gens, c&amp;#8217;est important de voir des êtres humains!&quot;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et ceci &lt;a href=&quot;https://twitter.com/CedricChampeau/status/1173893698997936130&quot;&gt;m&amp;#8217;a fait réagir&lt;/a&gt;, j&amp;#8217;aimerais donc revenir sur le sujet.
Tout d&amp;#8217;abord, revenons sur le fait que ce conseil ne fonctionne que si vous habitez en ville, ce qui n&amp;#8217;est pas mon cas.
Je suis en campagne, à 5km du bourg, donc faire une &quot;pause café&quot;, ça prend du temps dans ces conditions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais revenons surtout sur le fond du sujet: &quot;C&amp;#8217;est important de voir des êtres humains&quot;, ou ce &lt;em&gt;besoin de ne pas être seul&lt;/em&gt;.
C&amp;#8217;est un sujet qui me tient à coeur et qui résonne avec une des questions que j&amp;#8217;ai souvent lorsque je parle du télétravail:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&quot;Mais tu n&amp;#8217;en as pas marre d&amp;#8217;être tout seul, de ne voir personne ?&quot;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, répondons franchement: &lt;strong&gt;non&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Autant je comprends les personnes qui en ont besoin, autant, &lt;strong&gt;ne croyez pas que tout le monde fonctionne comme vous&lt;/strong&gt; et a &lt;em&gt;besoin&lt;/em&gt; de voir du monde.
Certaines personnes, comme moi, vivent très bien sans voir personne.
Je peux passer des journées entières seul, sans que celà ne me pose le moindre problème, ni ne me cause le quelconque manque de relations humaines.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je vais partie de cette catégorie de population qu&amp;#8217;on appelle les &lt;em&gt;introvertis&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un &lt;em&gt;introverti&lt;/em&gt;, contrairement à une croyance populaire, ça n&amp;#8217;est pas un associal, un égoïste ou quelqu&amp;#8217;un sans empathie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un &lt;em&gt;introverti&lt;/em&gt;, c&amp;#8217;est quelqu&amp;#8217;un dont l&amp;#8217;énergie sera drainée par la foule, par les relations inter-personnelles, c&amp;#8217;est l&amp;#8217;opposé d&amp;#8217;un &lt;em&gt;extraverti&lt;/em&gt; qui a besoin de monde pour regagner de l&amp;#8217;énergie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un &lt;em&gt;introverti&lt;/em&gt;, c&amp;#8217;est quelqu&amp;#8217;un qui ne supportera pas les conversations de comptoir, parce qu&amp;#8217;elles ne lui apportent rien d&amp;#8217;autre qu&amp;#8217;une perte d&amp;#8217;énergie.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un &lt;em&gt;introverti&lt;/em&gt;, c&amp;#8217;est quelqu&amp;#8217;un qui pourra vous tenir une conversation passionnée sur un sujet qui l&amp;#8217;intéresse, parce qu&amp;#8217;il en retire quelque chose: l&amp;#8217;interaction en vaut la chandelle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Déja tout petit, j&amp;#8217;évitais les groupes, je n&amp;#8217;avais pas beaucoup d&amp;#8217;amis (mais ceux que j&amp;#8217;avais à l&amp;#8217;époque, je les ai toujours).
J&amp;#8217;ai toujours eu une peur bleue de me retrouver dans un groupe où je ne connaissais personne, que ce soit à l&amp;#8217;école, au sport, &amp;#8230;&amp;#8203;
Mais même si je connaissais quelqu&amp;#8217;un, se retrouver &lt;em&gt;dans un groupe&lt;/em&gt;, à devoir cultiver des relations proches, extra &quot;professionnelles&quot;, était d&amp;#8217;une extrême complexité pour moi (et ça l&amp;#8217;est toujours).
Tout ce qui m&amp;#8217;importait à l&amp;#8217;époque, c&amp;#8217;était d&amp;#8217;apprendre, être &quot;fort&quot; à l&amp;#8217;école, ce qui m&amp;#8217;a valu d&amp;#8217;être traité &quot;d&amp;#8217;intello&quot;, parfois chahuté, ou d&amp;#8217;avoir des remarques pas particulièrement gentilles d&amp;#8217;autres élèves au dos de ma photo de classe, ceci pendant une grande partie de mon enfance&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Par exemple, j&amp;#8217;ai toujours refusé les camps de vacances (ma seule expérience, une semaine à faire du cheval, fût tellement une horreur pour moi que je m&amp;#8217;en souviens encore).
J&amp;#8217;ai aussi refusé toutes les classes de neige.
En revanche, j&amp;#8217;avais accepté d&amp;#8217;aller en voyage scolaire en Angleterre, en Irlande, en Espagne, non sans lutter contre moi-même, parce que je savais que je pouvais en tirer quelque chose, mais aussi parce que j&amp;#8217;avais la garantie de me retrouver en petit nombre, avec un copain, dans une chambre&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans la même veine, devoir se retrouver au tableau pour réciter une poésie, ou, pire, chanter, tenait de la torture.
J&amp;#8217;ai adoré la fac&apos; de sciences, parce que je pouvais passer du temps au &quot;café&quot; avec 2/3 potes maximum, à discuter.
J&amp;#8217;ai détesté mon école d&amp;#8217;ingénieur, où j&amp;#8217;ai du rivaliser d&amp;#8217;astuces pour éviter les soirées d&amp;#8217;intégration, tonus et autres dont étaient friants 95% des étudiants: se faire reconnaître sans se faire exclure (mais j&amp;#8217;ai encore trouvé quelques bons amis que je tiens de cette époque).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Aaah, les soirées d&amp;#8217;intégration: ce qui est marrant pour certains, se bourrer la gu&amp;#8230;&amp;#8203;, humilier &quot;gentilement&quot; les autres, c&amp;#8217;était juste pour moi quelque chose d&amp;#8217;horrible.
Tiens, d&amp;#8217;ailleurs, peu le savent, mais j&amp;#8217;ai fait toute ma scolarité à Nantes, non pas parce que tout était disponible là bas (c&amp;#8217;était le case), mais parce que j&amp;#8217;était terrifié à l&amp;#8217;idée de me retrouver seul dans une FAC, une école d&amp;#8217;ingénieur, à l&amp;#8217;autre bout de la France&amp;#8230;&amp;#8203;
Certains profs m&amp;#8217;avaient reproché de ne pas tenter une &quot;Grande Ecole&quot;, mais je pense qu&amp;#8217;au final, je m&amp;#8217;en suis plutôt bien sorti !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_jamais_je_nembaucherais_quelquun_comme_vous&quot;&gt;Jamais je n&amp;#8217;embaucherais quelqu&amp;#8217;un comme vous!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci pourrait vous paraitre surprenant pour quelqu&amp;#8217;un qui, aujourd&amp;#8217;hui, donne des conférences devant, parfois, des centaines de personnes.
Mais alors, quelle est la différence ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La différence, c&amp;#8217;est que lorsque je vous parle dans un cadre professionnelle, &lt;strong&gt;je maîtrise mon sujet&lt;/strong&gt; (ou je pense le maîtriser, ah ah !).
Je peux vous parler ouvertement, parce que je sais que les questions qu&amp;#8217;on va me poser seront sur ce sujet.
Il n&amp;#8217;y a que peu de place à l&amp;#8217;inconnu.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;C&amp;#8217;est aussi pour celà qu&amp;#8217;il m&amp;#8217;est très difficile, encore aujourd&amp;#8217;hui, d&amp;#8217;aborder des gens que je ne connais pas.
Je ne sais pas faire de &quot;small talk&quot;, comme on dit.
Mais ça va plus loin: j&amp;#8217;ai fais pas mal de déplacements à l&amp;#8217;étranger, aux US par exemple, mais JAMAIS, je ne suis sorti seul pour visiter (au mieux je marcherai une heure ou deux dans les alentours).
On rentre dans cette zone d&amp;#8217;inconnu qui me met tellement mal à l&amp;#8217;aise : devoir s&amp;#8217;adresser à des gens, qui plus est à l&amp;#8217;étranger, pour commander un plat, pour demander son chemin: celà me demande trop d&amp;#8217;efforts, me draine trop.
En revanche, si je connais une ou deux personnes et qu&amp;#8217;elle me proposent de les accompagner, ça se passera bien: j&amp;#8217;apprécie fortement une sortie en &quot;petit comité&quot;.
Tout le monde me dit que j&amp;#8217;ai tellement de chance de partir voyager, voir du pays, mais moi, je déteste tellement voyager, en tout cas sans ma famille&amp;#8230;&amp;#8203;
Rien qu&amp;#8217;aller à Paris, me rendre compte du nombre de personnes qui vivent là bas, me sentir étouffer, qu&amp;#8217;est-ce que j&amp;#8217;ai horreur de ça !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La conséquence, c&amp;#8217;est que je fuis comme la peste les &quot;soirées&quot; comme les speaker dinner, les événements d&amp;#8217;entreprise, &amp;#8230;&amp;#8203;
Souvent, on les présente comme des incontournables du &quot;réseautage&quot;, et c&amp;#8217;est vrai qu&amp;#8217;on y apprend souvent des choses intéressantes, mais elles sont extrêmement stressantes pour moi.
La plupart du temps, j&amp;#8217;essaie de trouver une tête connue et je &quot;m&amp;#8217;accroche&quot;, mais je ne fais jamais long feu.
Ce qui me terrorise s&amp;#8217;est d&amp;#8217;en arriver à des sujets extra-professionnels, là où je n&amp;#8217;ai AUCUNE &quot;compétence&quot;.
Certains diront que je suis chiant, que je n&amp;#8217;ai aucun intérêt, et c&amp;#8217;est probablement vrai si vous recherchez quelqu&amp;#8217;un à la vie extraordinaire, la mienne n&amp;#8217;est pas ultra passionnante :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si vous en arrivez là, vous devez vous dire que je ne dois pas être un très bon &quot;team player&quot;, comme on dit.
Paradoxalement je ne pense pas que ce soit le cas.
En effet, il ne faut pas confondre mon incapacité à avoir des relations inter-personnelles &quot;simples&quot; avec la capacité d&amp;#8217;échange, d&amp;#8217;interaction professionnelle, qui est sur une toute autre dimension.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comme je vous l&amp;#8217;ai expliqué, je donne régulièrement des talks, et j&amp;#8217;adore plus que tout partager ces connaissances, aider les autres.
J&amp;#8217;aime aussi travailler avec des gens plus compétents que moi pour avoir l&amp;#8217;autre face de la pièce: apprendre, comprendre de nouvelles choses, progresser.
Et dans ce contexte, travailler en équipe aide énormément.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, ce n&amp;#8217;est pas parce qu&amp;#8217;on est en télétravail et qu&amp;#8217;on ne voit personne qu&amp;#8217;on travaille &lt;em&gt;seul&lt;/em&gt;.
Non, on est en équipe. On fait des &quot;daily standup&quot; (via Hangout/Slack), on s&amp;#8217;organise, on fait des petites réunions &quot;face to face&quot; de temps en temps, bref, je pense, mes collègues vous le diront si ça n&amp;#8217;est pas le cas, que ça se passe plutôt bien.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, n&amp;#8217;ayez pas peur de cet aspect: la solitude n&amp;#8217;est pas, pour tout le monde, un problème.
Elle peut, au contraire, aider à la productivité: pas de réunionite inutile, capacité à se focaliser sur un problème des heures durant, &amp;#8230;&amp;#8203;
Elle n&amp;#8217;est pas, non plus, signe de quelqu&amp;#8217;un qui ne peut pas travailler en équipe: ça n&amp;#8217;empêche en RIEN d&amp;#8217;aider ses collègues, ses clients, bien au contraire: puisqu&amp;#8217;on sait que la relation est professionnelle, elle est focalisée et bien plus efficace.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour vous donner une idée, chez Gradle, tout le monde est en télétravail.
Mais pour cet aspect &quot;socialisation&quot;, nous avons une réunion hebdomadaire, facultative, appelée &quot;coffee time&quot; où chacun peut rejoindre la réunion et parler de sujets extra-professionnels.
Certains en ont besoin, pas moi.
Au contraire, j&amp;#8217;aurais du mal à arriver à cette réunion et savoir de quoi parler.
Pire, j&amp;#8217;évite au maximum d&amp;#8217;arriver en premier à une réunion de peur de ne pas savoir engager une conversation&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais encore une fois: parlez moi d&amp;#8217;un sujet que je maîtrise, demandez moi d&amp;#8217;expliquer un problème, de chercher une solution, d&amp;#8217;aider quelqu&amp;#8217;un: il n&amp;#8217;y aura aucun problème, parce qu&amp;#8217;il n&amp;#8217;y a aucune place à l&amp;#8217;inconnu.
Il est même fort probable que j&amp;#8217;apprécie énormément une conversation entre nous: si je ne viens pas vous voir, ça n&amp;#8217;est pas que je ne souhaite pas vous parler, c&amp;#8217;est que même si je vous connais, engager une conversation reste quelque chose de très compliqué pour moi. Venez me voir, engagez la conversation et tout se passera bien ! :D&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, ne vous étonnez pas si je vais trois fois le tour du quartier plutôt que de demander mon chemin.
Ne vous étonnez pas si je ne téléphone jamais, ne texte jamais.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais si vous faites partie de mes amis, vous avez énormément de chance: c&amp;#8217;est que je tiens beaucoup à vous et vous tiens en haute estime !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_nayez_pas_honte_dêtre_introvertis_faites_comprendre_ce_que_cest&quot;&gt;N&amp;#8217;ayez pas honte d&amp;#8217;être introvertis, faites comprendre ce que c&amp;#8217;est&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je terminerais pas une remarque: dans mon &lt;a href=&quot;https://twitter.com/CedricChampeau/status/1173893698997936130&quot;&gt;Tweet original&lt;/a&gt;, je disais que je &quot;me soignais&quot;.
C&amp;#8217;est vrai et c&amp;#8217;est faux à la fois.
Quand je dis que c&amp;#8217;est vrai, c&amp;#8217;est parce que conscient de l&amp;#8217;importance et de la &quot;non reconnaissance&quot; de cette difficulté par les autres, j&amp;#8217;essaie de travailler, notamment la prise de parole.
Je suis, par exemple, secrétaire du club de Karaté, ce qui me force à communiquer avec des gens que je ne connais pas.
Je suis aussi le coach de l&amp;#8217;équipe de basket de mon fils de 10 ans, ce que j&amp;#8217;adore faire: c&amp;#8217;est une activité avec son enfant, qui est à la fois publique, mais aussi tellement gratifiante, voir ces enfants heureux de jouer, gagner, &amp;#8230;&amp;#8203; et ça me permet de travailler sur les relations avec les parents !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et surtout, c&amp;#8217;est aussi un message pour mon fils, qui a 10 ans donc mais me ressemble tellement: il a lui aussi beaucoup de mal à parler aux gens, mais je qu&amp;#8217;il travaille dur pour se faire accepter. Lui aussi est si fier lorsqu&amp;#8217;il a la reconnaissance de ses pairs&amp;#8230;&amp;#8203; Il m&amp;#8217;a fallu des années avant de mettre un nom à ce que je suis, un &lt;em&gt;introverti&lt;/em&gt;, et aujourd&amp;#8217;hui encore, je lutte pour ne plus en avoir &lt;em&gt;honte&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Dependency Management at Gradle</title>
      <link>https://melix.github.io/blog//2019/07/dependency-management.html</link>
      <pubDate>Thu, 11 Jul 2019 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2019/07/dependency-management.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Opinions are my own, not those of my employer&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I joined Gradle 4 years ago, and I spent the last 2 years almost exclusively working on &lt;em&gt;dependency management&lt;/em&gt;.
The more I work on this topic, the more I am frustrated by the state of our industry.
In this blog post I will mostly illustrate my points with Java, which I&amp;#8217;m mostly familiar with, but a lot of them stand true whatever the ecosystem (Javascript, Python, Go, &amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Soon, we should release Gradle 6 (fall 2019, no promise, as always, this is software).
This version will be the first one to turn the spotlights on &lt;em&gt;dependency management&lt;/em&gt;.
This will be for me the achievement of 2 hard years of work (not alone, of course) but this is &lt;em&gt;just&lt;/em&gt; the beginning.
Gradle probably has the most advanced dependency engine of the market (forgive me if I&amp;#8217;m wrong, let me know).
But what makes it so different is not that it has powerful features like dependency substitution, customizable resolution, dependency locking, alignment, etc&amp;#8230;&amp;#8203;
No, what makes it different it&amp;#8217;s that we put a lot of emphasis on &lt;em&gt;semantics&lt;/em&gt;: model software correctly so that you, as a developer, have less to handle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Often, folks &quot;from the outside&quot; are considering us &lt;em&gt;arrogant&lt;/em&gt;, because we don&amp;#8217;t immediately support things that other engines do (eg. &quot;you don&amp;#8217;t want to implement optional dependencies, look, Maven has it for years you s***&quot;).
While I understand the frustration, it doesn&amp;#8217;t mean that we don&amp;#8217;t hear.
In fact, we hear you loud, but the time it takes to land is just the consequence of willing to implement the correct solution to a problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, what does an &lt;em&gt;optional dependency&lt;/em&gt; mean?
A few months ago, I read this from the Yarn documentation which got me scared, and, to be honest, a bit despaired too:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/optional-deps-yarn.png&quot; alt=&quot;optional deps yarn&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This looks like total non-sense to me.
Because we needed the infrastructure, it took some time but we implemented what we think is a &lt;em&gt;better&lt;/em&gt; solution.
In a nutshell, optional dependencies are &lt;em&gt;not optional&lt;/em&gt;.
They are things that you need &lt;em&gt;if you use a particular feature of a library&lt;/em&gt;.
So it means that if you depend on something, and that this something has &lt;em&gt;optional features&lt;/em&gt;, you can say what features you need and Gradle would give you the correct dependencies for this.
We called that &lt;a href=&quot;https://docs.gradle.org/current/userguide/feature_variants.html&quot;&gt;feature variants&lt;/a&gt;. Granted, the name isn&amp;#8217;t cool, but it&amp;#8217;s a matter of time until we refactor the documentation to make it easier to discover.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Similarly, we implemented back in Gradle 3.4 the separation of API and implementation dependencies for the Java world.
In fact, that&amp;#8217;s one of the reasons the &lt;code&gt;compile&lt;/code&gt; configuration has been &quot;soft deprecated&quot; for years now, and that we&amp;#8217;re going to nag you starting from Gradle 6.
I still hear people claiming they don&amp;#8217;t need this and that it&amp;#8217;s hard to understand but I stand by the fact they &lt;em&gt;deperately&lt;/em&gt; need them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Why is it important? Because if you are a library author, you know that there are things that are &quot;your internal sauce&quot;: things which are implementation details, not part of the public API, and that should never be exposed to consumers.
This is the very reason Java 9 shipped with the module system: strong encapsulation.
However, how does it work for dependencies? There are also dependencies which are &lt;em&gt;part of your API&lt;/em&gt; and others which are not.
Say you use Guave internally. None of the Guava classes are visible on your public API, and it would be an error to do so.
Then it means that Guava &lt;em&gt;is an implementation dependency of your library&lt;/em&gt;.
When you do this, you should be allowed to replace Guava with something else at any time, without breaking any of your consumers.
The horrible reality is that if you use the Maven &lt;code&gt;&amp;lt;compile&amp;gt;&lt;/code&gt; scope, those dependencies are going to &lt;em&gt;leak&lt;/em&gt; to the consumers, and they could accidentally start using Guava just because it&amp;#8217;s available on the classpath (yeah, IDEs love this, the class is available for completion you know!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is a problem with Maven because the POM file is used for 2 distinct purposes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;representing the point of view of the producer, where &lt;code&gt;&amp;lt;compile&amp;gt;&lt;/code&gt; means &quot;I need this on my compile classpath&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;representing the point of view of the consumer, where &lt;code&gt;&amp;lt;compile&amp;gt;&lt;/code&gt; semantics are there broken: it means &quot;add this to your compile classpath&quot;, but it means you leak dependencies which should have been on the &lt;code&gt;&amp;lt;runtime&amp;gt;&lt;/code&gt; scope!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the Gradle &lt;a href=&quot;https://docs.gradle.org/current/userguide/java_library_plugin.html&quot;&gt;Java Library plugin&lt;/a&gt;, those issues &lt;em&gt;go away&lt;/em&gt;: we model those correctly, and when we generate a POM file, it has dependency declarations which &lt;em&gt;make sense for the consumer&lt;/em&gt;.
I&amp;#8217;ve been battling to explain this in conferences for years, yet, lots of people don&amp;#8217;t get how harmful to the whole ecosystem that design decision from Maven was: it just prevents smooth dependency upgrades, and contributes to the &quot;classpath explosion&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In other words, you, as a developer, should &lt;em&gt;always know what you directly use&lt;/em&gt; (your first level dependencies).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As another example, we&amp;#8217;ve been yelling for years how bad exclusions are, but we did a really bad job at explaining &lt;em&gt;why&lt;/em&gt;.
The problem is also that we didn&amp;#8217;t have all the tools we needed to workaround them, so we said &quot;yeah it&amp;#8217;s bad&quot; but didn&amp;#8217;t really say that you can still use them in some cases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In a nutshell, an &lt;em&gt;exclusion&lt;/em&gt; is bad because the dependency resolution engine doesn&amp;#8217;t know &lt;em&gt;why&lt;/em&gt; you excluded a dependency:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;is it because the producer had bad metadata, that the dependency should have been &quot;optional&quot;, or just absent altogether?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;is it because you don&amp;#8217;t use a specific &lt;em&gt;code path&lt;/em&gt; of a dependency and you just want to slim down the size of your distribution?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;is it because &lt;em&gt;something breaks&lt;/em&gt; if you use this dependency?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;is it because it&amp;#8217;s yet another logger on the classpath and this is not the one you use?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, again, for all those use cases, the solutions are &lt;em&gt;different&lt;/em&gt;.
The logging use case is an illustration of this: how many of you have faced this infamous problem of having multiple SLF4J bindings on the classpath?
How do you fix that with Maven? Exclude of course!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But wouldn&amp;#8217;t it better if you could express that &quot;between all those logger bindings, this is the one I choose&quot;.
Wouldn&amp;#8217;t it better if, as a &lt;em&gt;producer&lt;/em&gt; of a logger binding, you could say &quot;I implement this logger API, and it doesn&amp;#8217;t make sense to have multiple logger bindings on the classpath at the same time&quot;.
Well, this is what Gradle offers you, as a producer and as a consumer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Modeling software is important, because it makes the industry better &lt;em&gt;as a whole&lt;/em&gt;.
By explaining &lt;em&gt;why&lt;/em&gt; instead of &lt;em&gt;how&lt;/em&gt;, &lt;strong&gt;the dependency management engine can take better decisions&lt;/strong&gt;.
It can fail if things are incompatible, it can ask you to choose between different implementations.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Do you need another example? Look at all those &quot;Maven classifiers&quot;. How many times did you got multiple conflicting implementations of the same thing &lt;em&gt;just because they had different classifiers&lt;/em&gt; (looking at you, Guava!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The reality is that a classifier is a workaround for a bad model, incapable of expressing that you have different &lt;em&gt;things&lt;/em&gt; published at the same coordinates.
Sometimes I read comments like &quot;Gradle is just Maven with a Groovy DSL&quot;.
This is wrong at so many levels: Gradle empathizes on &lt;em&gt;strong modelling&lt;/em&gt; of software.
We need to think in terms of components (&quot;this is a library&quot;, &quot;this is a Boot application&quot;, &quot;this is a Gradle plugin&quot;), not in terms of &lt;em&gt;conventions&lt;/em&gt;.
Models are orthogonal to conventions: conventions are just a tool to make modelling easier to implement, but what matters is the model.
The DSL also doesn&amp;#8217;t matter: Groovy, Kotlin, whatever. What makes Gradle powerful is that it &lt;em&gt;understands what you build&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is one of the reasons we came with &lt;a href=&quot;https://blog.gradle.org/gradle-metadata-1.0&quot;&gt;Gradle Module Metadata&lt;/a&gt;, which is going to be enabled by default in Gradle 6.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We, at Gradle, think that we can save a lot of developer time by simply putting more sense in those things we publish.
It&amp;#8217;s a waste of time and energy that we all have to fix, constantly, those conflicts between libraries.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And can we talk about ethics?
It&amp;#8217;s beyond me we can tolerate, as developers/engineers, repeated approximations, errors, just &lt;em&gt;because Maven does it this way&lt;/em&gt;?
I don&amp;#8217;t really care that we&amp;#8217;re &lt;em&gt;not compatible with Maven&lt;/em&gt;, as long as we &lt;em&gt;solve the problem&lt;/em&gt; and that we move towards well designed, better solutions.
Sometimes we have to make tradeoffs, but we can&amp;#8217;t compromise on reproducibility, correctness and performance.
Of course, we do our best to provide Maven compatibility, and again, sometimes make it even better in some situations (the Java Library plugin).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My goal is that we, as a whole, move towards a better software delivery world.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The good thing is that what we&amp;#8217;re not alone.
This, is the result of years of experience from the team with very large builds, from customers of small to very large organizations, and discussions with talented open-source developers (special thanks from me to &lt;a href=&quot;https://twitter.com/ankinson&quot;&gt;Andy Wilkinson&lt;/a&gt; from the Spring team).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I posted this earlier this month on Twitter, this is a &lt;em&gt;real&lt;/em&gt; dependency graph, from an organization I have the opportunity to work with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/real-dependency-graph.png&quot; alt=&quot;real dependency graph&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is not uncommon, this is the reality we live in.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And when you have such a dependency graph, you desperately need more modelling.
Does it mean that Gradle is perfect? Hell, no. We&amp;#8217;re going to make mistakes, we already have and we will continue, but what matters is that we&amp;#8217;re moving towards our goal.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are lots of good things coming in Gradle 6, stay tuned. In the meantime, a lot of what I discussed here has been presented in a couple of webinars:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://gradle.com/blog/dependency-management-fundamentals/&quot;&gt;Dependency Management fundamentals with Gradle&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://gradle.com/blog/dependency-management-part-2-handling-conflicts/&quot;&gt;Handling Conflicts and Customizing Resolution&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another webinar is planned after summer, around multi-repository development.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hope you&amp;#8217;ll enjoy!&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Goodbye, Groovy!</title>
      <link>https://melix.github.io/blog//2019/03/goodbye-groovy.html</link>
      <pubDate>Thu, 21 Mar 2019 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2019/03/goodbye-groovy.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_im_stepping_down_from_the_apache_groovy_project&quot;&gt;I&amp;#8217;m stepping down from the Apache Groovy project&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today is a very sad day. I&amp;#8217;ve decided to resign from the Apache Groovy PMC, as well as a committer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The trigger was that I &lt;a href=&quot;https://github.com/apache/groovy/commit/56c219eca0c028c95713a3abd74f14fa40cb0e6c&quot;&gt;dared pushing a Gradle Kotlin DSL&lt;/a&gt; and this had to be reverted.
Lots of people in the Groovy community see Kotlin as a threat. I don&amp;#8217;t. I use both languages everyday, for different purposes.
I wrote most of the static compiler for Groovy, and I have no problem saying that I believe Kotlin is better as a static language: the experience is more consistent, and very pleasant.
But nothing in Kotlin reaches the simplicity that Groovy offers. Running a single line script, the awesome Spock framework for testing, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The fact I work for Gradle Inc was also mentioned as a reason why I did push this file.
To me, this is questioning my integrity, which is something I cannot accept.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In practice, since Gradle announced a couple of years back that they would start using Kotlin as a language for its DSL, I&amp;#8217;ve been in a very complicated position.
Privately, I always get pinged whenever I say something good about Kotlin. Like, you should not do this, this is not good for us, or, Gradle is not nice with Groovy, what are you doing.
People always make jokes about Kotlin when they talk to me. I was at Gr8Conf Europe a few days after the announcement and man, that wasn&amp;#8217;t a pleasant experience.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am Cédric. I am not Gradle Inc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am Cédric. I am not Kotlin.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am Cédric. I am not Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Technologies live and die, I&amp;#8217;m not interested in being married with a technology, I&amp;#8217;m interested in working with something that excites me.
The reality is that I&amp;#8217;ve been more excited with Kotlin than Groovy lately, and the attacks, conscious or not, public or private, that I get everytime I mention this language are tiring.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, when I&amp;#8217;m going to say something good about Groovy, I hope folks will believe me.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_special_thanks&quot;&gt;Special thanks&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I want to thank Guillaume Laforge for this adventure. Man, you gave me the opportunity to join the project, its awesome community. You gave me a job, I was lucky enough to be paid to work on open-source software, and that&amp;#8217;s all because of you. For that I owe you everything, thank you!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Second, thanks to Paul King. You are the one that the Groovy community should never loose. People have mentioned that I would be a great loss, but that&amp;#8217;s not true: the reality is that I contributed almost nothing recently, and you did all the hard work. You are also an amazing person always trying to get the best of us. I will miss it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then Jochen Theodorou: thanks to you for all the hard work you&amp;#8217;ve done with the compiler. I would not have been able to write the static compiler without your help and insights on the internals of Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I&amp;#8217;d also would like to personally thank folks that make the community vibrant: Søren Berg Glasius, Graeme Rocher, Jeff Scott Brown, Iván López, Álvaro Sánchez and all the others I miss, don&amp;#8217;t take it personally, this is not easy for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, thank you to the Groovy community. You&amp;#8217;ve been awesome, and I wouldn&amp;#8217;t be where I am without you. I may have been a bit sharp saying that the Groovy community as a whole sees me as a Trojan horse, that&amp;#8217;s not true, but the truth is that I don&amp;#8217;t want to fight anymore. Do not assume that because I quit the community is toxic: it&amp;#8217;s not. There&amp;#8217;s just a lot of understandable fear for the future, in my opinion. My advice is, embrace the change, don&amp;#8217;t look back, and take inspiration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I want to say good luck to the team, in particular to its newer members, like Daniel Sun, who are the future of this language: they have the energy, the skills to make it better.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, I&amp;#8217;m still a &lt;a href=&quot;https://opencollective.com/friends-of-groovy&quot;&gt;friend of Apache Groovy&lt;/a&gt;, you should be too!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A simple native HTTP server with GraalVM</title>
      <link>https://melix.github.io/blog//2019/03/simple-http-server-graal.html</link>
      <pubDate>Tue, 19 Mar 2019 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2019/03/simple-http-server-graal.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_writing_a_simple_http_server_with_graalvm&quot;&gt;Writing a simple HTTP server with GraalVM&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my daily work, I often need to start a simple HTTP server to serve local files.
For example, this week I&amp;#8217;m going to give a talk at &lt;a href=&quot;https://www.breizhcamp.org&quot;&gt;Breizcamp&lt;/a&gt;, and because my presentation uses a &lt;a href=&quot;https://revealjs.com&quot;&gt;Reveal.js slide deck&lt;/a&gt; and that it loads resources dynamically, I need a &quot;real&quot; web server to serve the files.
So far, I&amp;#8217;ve been quite happy using the Python simple http server.
Using it is as easy as running:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;python -m SimpleHTTPServer 8000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But knowing that the JDK has an embedded HTTP server, and that there&amp;#8217;s a lot of hype around Graal those days, I wanted to see if we could achieve the same thing, with a fast startup, with GraalVM.
The answer is &lt;strong&gt;yes&lt;/strong&gt;, but the road wasn&amp;#8217;t so easy, at least for Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_show_me_the_code&quot;&gt;Show me the code&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code for this experiment can be found on &lt;a href=&quot;https://github.com/melix/graal-simple-httpserver&quot;&gt;GitHub&lt;/a&gt;.
We&amp;#8217;re going to use:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt; to build&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;a href=&quot;https://github.com/palantir/gradle-graal&quot;&gt;Gradle Graal plugin&lt;/a&gt; from Palantir&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And because I like the &lt;a href=&quot;https://www.groovy-lang.org/&quot;&gt;Groovy&lt;/a&gt;, and especially its static compiler, my first attempt was to use statically compiled Groovy to do this.
Well, it turned out to become a nightmare, so after an hour trying to make it work, I switched to Kotlin, and try to make it work there first.
Knowing that Kotlin is a statically compiled language from the ground up and that it doesn&amp;#8217;t have the whole dynamic history of Groovy, I did expect it to be simpler.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, in the end, here&amp;#8217;s what the Kotlin server looks like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;HttpServer.kt&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;fun main(args: Array&amp;lt;String&amp;gt;) {
    val port = if (args.size &amp;gt; 0) args[0].toInt() else 8080
    val baseDir = if (args.size &amp;gt; 1) File(args[1]).canonicalFile else File(&quot;.&quot;).canonicalFile

    create(InetSocketAddress(port), 0).run {
        createContext(&quot;/&quot;) { exchange -&amp;gt;
            exchange.run {
                val file = File(baseDir, requestURI.path).canonicalFile
                if (!file.path.startsWith(baseDir.path)) {
                    sendResponse(403, &quot;403 (Forbidden)\n&quot;)
                } else if (file.isDirectory) {
                    val base = if (file == baseDir) &quot;&quot; else requestURI.path
                    sendResponse(200, &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&quot; +
                            file.list()
                                .map { &quot;&amp;lt;ul&amp;gt;&amp;lt;a href=\&quot;$base/${it}\&quot;&amp;gt;${it}&amp;lt;/a&amp;gt;&amp;lt;/ul&amp;gt;&quot; }
                                .joinToString(&quot;\n&quot;) + &quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;)

                } else if (!file.isFile) {
                    sendResponse(404, &quot;404 (Not Found)\n&quot;)
                } else {
                    sendResponse(200) {
                        FileInputStream(file).use {
                            it.copyTo(this)
                        }
                    }
                }
            }
        }
        executor = null
        println(&quot;Listening at https://localhost:$port/&quot;)
        start()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s quite simple indeed, and making this work as a GraalVM native image is extremely easy too. This is the &lt;em&gt;whole build file&lt;/em&gt;, this is all you need:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle.kts&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;plugins {
   kotlin(&quot;jvm&quot;) version &quot;1.3.21&quot;
   id(&quot;com.palantir.graal&quot;) version &quot;0.3.0-6-g0b828af&quot;
}

repositories {
   jcenter()
}

dependencies {
   implementation(kotlin(&quot;stdlib&quot;))
}

graal {
   graalVersion(&quot;1.0.0-rc14&quot;)
   mainClass(&quot;HttpServerKt&quot;)
   outputName(&quot;httpserv-kt&quot;)
   option(&quot;--enable-http&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, we just apply the Kotlin plugin to build our code, then the GraalVM plugin and configure the basics of the GraalVM plugin (version, main class, &amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Building the image can be done by calling:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;./gradlew http-kotlin:nativeImage&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As &lt;a href=&quot;https://scans.gradle.com/s/nzkvn2gwkguf6&quot;&gt;you can see&lt;/a&gt;, building the whole thing takes around 15s on my laptop.
That is to say, compiling the server &lt;strong&gt;and&lt;/strong&gt; generating the native image.
Then you can try to serve files running:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;http-kotlin/build/graal/httpserv-kt 9090 /path/to/files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You&amp;#8217;ll see that the server starts immediately: there&amp;#8217;s absolutely no wait time, it&amp;#8217;s there and ready to answer.
The whole process took me less than 30 minutes, the native image is only 11MB. Success!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_making_it_work_with_groovy&quot;&gt;Making it work with Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that I had a proof-of-concept with Kotlin, I went back to Groovy.
And, I can say, despite the fact I love this language, that it was a nightmare to make it work.
At some point, I even thought of abandoning, however, using perseverance, I managed to work around all problems I faced.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before I explain the problems, let&amp;#8217;s took a look at the final Groovy server:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;HttpServerGroovy.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@CompileStatic
abstract class HttpServerGroovy {

    // VERY dirty trick to avoid the creation of a groovy.lang.Reference
    static File baseDir

    static void main(String[] args) {
        def port = args.length &amp;gt; 0 ? args[0].toInteger() : 8080
        baseDir = args.length &amp;gt; 1 ? new File(args[1]).canonicalFile : new File(&quot;.&quot;).canonicalFile

        def server = HttpServer.create(new InetSocketAddress(port), 0)
        server.createContext(&quot;/&quot;, new HttpHandler() {
            @Override
            void handle(HttpExchange exchange) throws IOException {
                def uri = exchange.requestURI
                def file = new File(baseDir, uri.path).canonicalFile
                if (!file.path.startsWith(baseDir.path)) {
                    sendResponse(exchange, 403, &quot;403 (Forbidden)\n&quot;)
                } else if (file.directory) {
                    String base = file == baseDir ? &apos;&apos;: uri.path
                    String listing = linkify(base, file.list()).join(&quot;\n&quot;)
                    sendResponse(exchange, 200, String.format(&quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;%s&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&quot;, listing))

                } else if (!file.file) {
                    sendResponse(exchange, 404, &quot;404 (Not Found)\n&quot;)
                } else {
                    sendResponse(exchange, 200, new FileInputStream(file))
                }
            }
        })
        server.executor = null
        System.out.println(String.format(&quot;Listening at https://localhost:%s/&quot;, port))
        server.start()
    }

    private static List&amp;lt;String&amp;gt; linkify(String base, String[] files) {
        def out = new ArrayList&amp;lt;String&amp;gt;(files.length)
        for (int i = 0; i &amp;lt; files.length; i++) {
            String file = files[i]
            out &amp;lt;&amp;lt; String.format(&quot;&amp;lt;ul&amp;gt;&amp;lt;a href=\&quot;%s/%s\&quot;&amp;gt;%s&amp;lt;/a&amp;gt;&amp;lt;/ul&amp;gt;&quot;, base, file, file)
        }
        out
    }
    ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first thing you will notice is that it&amp;#8217;s far from being idiomatic Groovy.
Of course I used &lt;code&gt;@CompileStatic&lt;/code&gt;, because the static nature of GraalVM would have made this an even greater challenge to make it work with dynamic Groovy.
However, I didn&amp;#8217;t expect that it would be &lt;em&gt;so hard&lt;/em&gt; to make it work.
The resulting file is both a consequence of limitations of GraalVM, and historical background of Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_where_are_my_closures&quot;&gt;Where are my closures?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first code I wrote was using idiomatic Groovy, with closures. However, as soon as I started to build my native image, I noticed this obscure error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Invoke with MethodHandle argument could not be reduced to at most a single call: java.lang.invoke.MutableCallSite.&amp;lt;init&amp;gt;(MethodHandle)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It&amp;#8217;s funny to see this &lt;code&gt;MethodHandle&lt;/code&gt; error when you know that the code is &lt;em&gt;fully statically compiled&lt;/em&gt;, and that it doesn&amp;#8217;t contain a single method handle.
However, the Groovy runtime does, and this is where the fun began.
First of all, GraalVM tells you what method is problematic. This was &lt;code&gt;org.codehaus.groovy.vmplugin.v7.IndyInterface.invalidateSwitchPoints&lt;/code&gt;.
Things are getting a little clearer: for some reason, the Groovy runtime is initialized, and we load the dynamic &lt;code&gt;IndyInterface&lt;/code&gt;, that I won&amp;#8217;t ever need.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &quot;some reason&quot; needs a bit of explanation. Despite the fact that we use statically compiled Groovy, we&amp;#8217;re still implementing &lt;em&gt;Groovy specific interfaces&lt;/em&gt;. For example, the &lt;code&gt;GroovyObject&lt;/code&gt; interface.
Similarly, we honor class initialization the same way as a dynamic class, meaning that when a statically compiled Groovy class is instantiated, even if it doesn&amp;#8217;t contain any dynamic reference, we will initialize its metaclass, and as a consequence try to initialize the Groovy runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However something was &lt;em&gt;wrong&lt;/em&gt;: looking at my code I could not figure out what would cause initialization, because my entry point was static.
In fact, the answer was easy: it came through the closures.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, that&amp;#8217;s what I thought, because even after eliminating closures, I still got the damn error.
In fact, it turns out the situation is far more complex.
For example, I had this innocent looking code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def baseDir = args[0]
server.createContext(&quot;/&quot;, new HttpHandler() {
    @Override
    void handle(HttpExchange exchange) throws IOException {
        ...
        someCodeUses(baseDir)
    })&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The fact that we use &lt;code&gt;baseDir&lt;/code&gt; &lt;em&gt;within&lt;/em&gt; an anonymous inner class, and that Groovy uses the same code generation under the hood for both closures and anonymous inner classes, that the &lt;code&gt;baseDir&lt;/code&gt; variable is allowed to be mutated in the inner class. Of course here I&amp;#8217;m not doing it, but because the compiler doesn&amp;#8217;t eliminate that possibility, what it does is generating a &lt;code&gt;groovy.lang.Reference&lt;/code&gt; for my local variable, that is used in the inner class.
And, initializing the &lt;code&gt;Reference&lt;/code&gt; class would cause an additional path to this &lt;code&gt;IndyInterface&lt;/code&gt; method call&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, the problem is not that much that there&amp;#8217;s a &lt;code&gt;MethodHandle&lt;/code&gt;, it&amp;#8217;s that there are potentially different code paths that lead to this, and that GraalVM can&amp;#8217;t figure out in the end a single method to be called: we&amp;#8217;re just defeating the system!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, even creating an anonymous inner class would still trigger the creation of a metaclass for it: this means that even if we replace the closure with an inner class, in the end, we would still trigger the initialization of the Groovy runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I tried to be smart and remove the &lt;code&gt;IndyInterface&lt;/code&gt; from the code that GraalVM is using to generate the native image, knowing that in the end, this code would &lt;em&gt;never&lt;/em&gt; be called if I didn&amp;#8217;t register the Java 7 plugin (that I wouldn&amp;#8217;t use in any case). However, it turns out that GraalVM doesn&amp;#8217;t like this, as it has special handling for Groovy, and that if you &lt;em&gt;remove&lt;/em&gt; that class, it fails with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;Error: substitution target for com.oracle.svm.polyglot.groovy.Target_org_codehaus_groovy_vmplugin_v7_IndyInterface_invalidateSwitchPoints is not loaded. Use field `onlyWith` in the `TargetClass` annotation to make substitution only active when needed.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So instead I spent hours eliminating those paths, which involved:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;turning that shared variable into a field in order to workaround the reference initialization&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;removing all closures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;removing usages of &lt;code&gt;GString&lt;/code&gt; (interpolated strings, which is why you see &lt;code&gt;String.format&lt;/code&gt; instead)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;replacing the short-hand syntax for creating lists (&lt;code&gt;def foo=[]&lt;/code&gt;) with an explicit call&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;removing calls to &lt;code&gt;+&lt;/code&gt; with strings (first attempt to remove GString&amp;#8230;&amp;#8203;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;eliminating some classes from the Groovy runtime&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;replacing some classes of the Groovy runtime with stubs, preventing static initialization&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, I have &lt;a href=&quot;https://github.com/melix/graal-simple-httpserver/blob/master/http-groovy/build.gradle.kts&quot;&gt;something which works&lt;/a&gt;, but you can see that the build file is far more complex.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, it makes use of a little known Gradle feature called &lt;em&gt;artifact transforms&lt;/em&gt;. Basically, I&amp;#8217;m asking Gradle to transform the Groovy jar &lt;em&gt;before&lt;/em&gt; GraalVM uses it. This transformation involves filtering out classes, so that GraalVM doesn&amp;#8217;t try to be too smart about them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Once this is done, we can finally generate a native image for Groovy too:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;./gradlew http-groovy:nativeImage&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It takes about &lt;a href=&quot;https://scans.gradle.com/s/p4ctmi5pzune4&quot;&gt;the same amount of time as with Kotlin&lt;/a&gt; to generate a similar 11MB native image.
Running it is as easy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;pygments highlight&quot;&gt;&lt;code&gt;http-groovy/build/graal/httpserv-groovy 9090 /path/to/files&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And again it&amp;#8217;s super snappy!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this stage, you might consider that it&amp;#8217;s a success: we got both Kotlin and Groovy code compiled into a native image that is very snappy and starts even faster than the Python server.
However, getting the Groovy version to work was &lt;em&gt;hours of pain&lt;/em&gt;. Each time I managed to fix a problem, another one arose.
Basically, every method call, every extension method you call is likely to trigger initialization of some Groovy subsystem, or trigger additional paths to this &lt;code&gt;IndyInterface&lt;/code&gt; code.
In the end it would be nice if GraalVM could completely eliminate the need for having this class, but until then I just cannot recommend anyone to use Groovy to build native images: it&amp;#8217;s just &lt;em&gt;too frustrating&lt;/em&gt;.
And remember that even if you manage to make it work, it takes both a significant amount of time to do so, but also forces you to write non idiomatic code.
Last but not least, &lt;em&gt;any&lt;/em&gt; addition to your code is likely to force you to update your GraalVM configuration to make it work.
In the end, it&amp;#8217;s just way easier to write plain old Java code, or go Kotlin.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that I&amp;#8217;m not saying that it&amp;#8217;s not possible with Groovy, but &lt;a href=&quot;https://e.printstacktrace.blog/graalvm-and-groovy-how-to-start/&quot;&gt;folks usually face different problems than I did&lt;/a&gt;, in particular when it&amp;#8217;s just about configuring classes accessed by reflection: this is a simple problem.
I&amp;#8217;m not saying either that you should avoid Groovy: I just think it&amp;#8217;s not suited for this use case. I still use Groovy everyday, in particular in tests or for simple scripts (in replacement to bash scripts). However, more worrisome is that if an application transitively depends on Groovy, it&amp;#8217;s unlikely to be &quot;GraalVM compatible&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, if you look at the Kotlin version and the companion Gradle build, it&amp;#8217;s extremely simple, thanks to the great work done by the Palantir team!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
After this blog post was published, I received a &lt;a href=&quot;https://github.com/melix/graal-simple-httpserver/pull/1&quot;&gt;pull request from Szymon Stepniak&lt;/a&gt; improving the Groovy code a lot. The resulting file is, however, twice as big (23MB!). It does &lt;em&gt;not&lt;/em&gt; change my vision on this either, because it took 2 men to reach this point, in a significant amount of time.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle myth busting: lifecycle</title>
      <link>https://melix.github.io/blog//2018/09/gradle-lifecycle.html</link>
      <pubDate>Tue, 11 Sep 2018 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2018/09/gradle-lifecycle.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_build_lifecycle&quot;&gt;The build lifecycle&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There&amp;#8217;s a very common misconception I read from Maven users about Gradle: that there&amp;#8217;s no default lifecycle. Not only this is &lt;a href=&quot;https://scans.gradle.com/s/alokg5xymahwa/timeline?task=345te4gku5gw4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;wrong&lt;/a&gt;, but actually the Gradle lifecycle is significanly richer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, let&amp;#8217;s explain in a few words what the lifecycle is in Maven. Detailed explanations can be found &lt;a href=&quot;https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html&quot; target=&quot;&lt;em&gt;blank&quot;&gt;here&lt;/a&gt;, but in a nutshell, the idea is that _any&lt;/em&gt; build will always consist in a sequence of phases, and that each phase is built on top of the previous one. This has the advantage of being simple to explain: to deploy an application, you first need compile it, run the tests, package it, perform validation (checkstyle, &amp;#8230;&amp;#8203;) and deploy. Let me ignore &lt;em&gt;install&lt;/em&gt; which is an artifact of how Maven works.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Maven plugins attach themselves to those lifecycle phases, and define goals on different phases. For example, a code generator would attach itself to the &lt;code&gt;generate-sources&lt;/code&gt; phase, and define a &lt;em&gt;goal&lt;/em&gt; that runs at this phase. Fun begins when you have dependencies between the goals, and ordering matters&amp;#8230;&amp;#8203; Anyway, the general idea is that if you want to get the outcome of, say, packaging, you have to execute all previous phases and consequently all goals that are defined on those phases. The other consequence is that the Maven lifecycle is biased towards the Java model, and more specifically, building Java libraries. It&amp;#8217;s even clearer when you think about the term &lt;code&gt;deploy&lt;/code&gt;, which doesn&amp;#8217;t mean &quot;deploy this application on production&quot;, but &quot;push this jar on the external Maven repository&quot;. Similarly &quot;install&quot; doesn&amp;#8217;t mean &quot;install this application on my laptop&quot;, but &quot;copy this library into my local .m2 repository&quot;. This, I would argue, is rather counter-intuitive&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle, on the other hand, is a generic build tool. It&amp;#8217;s aimed at the Java ecosystem, but also the native one, the Android ecosystem, Python, Go, &amp;#8230;&amp;#8203; It doesn&amp;#8217;t matter. All of those ecosystems have an underlying model, and the way you build applications or libraries in each of those ecosystems is different. Gradle offers the APIs to &lt;em&gt;model the builds&lt;/em&gt; of each ecosystem. This flexibility is often what troubles Maven users, and makes them think there&amp;#8217;s no lifecycle, but it&amp;#8217;s not true.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_goals_vs_tasks&quot;&gt;Goals vs tasks&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To understand why, we need to explain that Gradle model is not &lt;em&gt;phase&lt;/em&gt; based, but &lt;em&gt;task&lt;/em&gt; based. It&amp;#8217;s a bit like what Ant did, but the similarity stops there. While Ant didn&amp;#8217;t define &lt;em&gt;any&lt;/em&gt; convention, &lt;em&gt;any&lt;/em&gt; lifecycle, and everything was different from one build to the other, this is not true with Gradle. By default, if you apply this &quot;Java library&quot; plugin, you&amp;#8217;ll get &lt;em&gt;all the conventions you find with Maven&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;plugins {
   id &apos;java-library&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the minimal build file you need to build, test and package a Java library with Gradle, with the same conventions as Maven &lt;code&gt;src/main/java&lt;/code&gt;, &amp;#8230;&amp;#8203; By applying this plugin, Gradle internally applies a sequence of plugins, which, in turn, would define new tasks, and more specifically for the topic of this blog post, &lt;em&gt;lifecycle tasks&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Gradle, a task is responsible for executing a unit of work. For example, &quot;compile this source set&quot;. A task has inputs (the source files) and outputs (the class files). But a task also has &lt;em&gt;dependencies&lt;/em&gt;. In particular, dependencies on other tasks. Gradle makes sure that a task graph is a DAG (direct, acyclic graph). This means that if you run &lt;code&gt;compile&lt;/code&gt; on the command-line, what Gradle does is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;compute the task dependencies of &lt;code&gt;compile&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;execute the tasks &lt;em&gt;in order&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Task dependencies can be explicit (say, &lt;code&gt;compile.dependsOn(compileJava)&lt;/code&gt;), or implicit (because you add a source set as an input, &lt;strong&gt;and&lt;/strong&gt; that this source set is generated by another task, then we know we need to run the code generation &lt;em&gt;for this source set&lt;/em&gt; before). This model is nice because it&amp;#8217;s significantly more fine grained than the phase one. When you execute a task, Gradle will always perform the minimal amount of work required to get the output of this task. Let&amp;#8217;s illustrate with an example: say you want to run the unit tests of your library. You would run the &lt;code&gt;test&lt;/code&gt; task with Gradle. Gradle would then determine that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it needs to compile the sources of the library (&lt;code&gt;compileJava&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;but the sources includes a generated source set, so it needs to execute it (&lt;code&gt;generateSources&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it would also find that the &quot;resources&quot; are an input of the test classpath, so execute the &lt;code&gt;processResources&lt;/code&gt; task&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;etc&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But, in the end, it would &lt;em&gt;not&lt;/em&gt; generate the jar file. Because Gradle knows that to run the tests, there&amp;#8217;s no need to get the jar: we can build a classpath that consists of the generated classes and the resources directories. It&amp;#8217;s actually very easy to figure out what the task dependencies are by running with &lt;code&gt;--dry-run&lt;/code&gt;, or using a &lt;a href=&quot;https://scans.gradle.com/s/mfihmuxqj2b2u/dependencies?focusedDependency=WzE3LDEsNTgsWzE3LDEsWzIzNiw1OF1dXQ&amp;amp;toggled=W1s4XSxbMTddLFsxNywxXSxbMTcsMSxbMjM2XV1d&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;build scan&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_so_will_you_tell_me_what_the_lifecycle_of_gradle_is_then&quot;&gt;So, will you tell me what the lifecycle of Gradle is then?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the trick. With Gradle, everything boils down to tasks, which are a bit like functions, with inputs and outputs. But there are special kinds of tasks, that we call &quot;lifecycle tasks&quot;, which are &lt;em&gt;binding other tasks together&lt;/em&gt;. They, effectively, produce no output individually. Their only role is to have dependencies on other tasks, so that we have nice shortcuts to produce our outputs. For example, the &lt;code&gt;check&lt;/code&gt; task is a lifecycle task which has dependencies on the &lt;code&gt;test&lt;/code&gt; task, but also the &lt;code&gt;checkstyle&lt;/code&gt; task, etc&amp;#8230;&amp;#8203; Plugins are free to add dependencies to the &lt;code&gt;check&lt;/code&gt; task, and &lt;em&gt;enrich&lt;/em&gt; the check lifecycle this way. But even better, by defining dependencies between tasks like that, and clearly defining the inputs and outputs of each task, we make it possible to get &lt;em&gt;correct&lt;/em&gt; incremental builds, as well as &lt;em&gt;caching&lt;/em&gt; (and no, this &lt;a href=&quot;https://docs.gradle.org/current/userguide/build_cache.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;has nothing to do with &lt;code&gt;~/.m2&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The good news is that because lifecycle tasks are just regular tasks, it means they can also depend on each other, and you can build your own lifecycle tasks. It becomes very easy to model your build production pipeline. So here is a simple correspondance matrix for Maven users, for the Java library plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;table class=&quot;tableblock frame-all grid-all stretch&quot;&gt;
&lt;caption class=&quot;title&quot;&gt;Table 1. Lifecycle correspondance matrix&lt;/caption&gt;
&lt;colgroup&gt;
&lt;col style=&quot;width: 33.3333%;&quot;&gt;
&lt;col style=&quot;width: 33.3333%;&quot;&gt;
&lt;col style=&quot;width: 33.3334%;&quot;&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th class=&quot;tableblock halign-left valign-top&quot;&gt;Maven&lt;/th&gt;
&lt;th class=&quot;tableblock halign-left valign-top&quot;&gt;Gradle&lt;/th&gt;
&lt;th class=&quot;tableblock halign-left valign-top&quot;&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;clean&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;clean&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Removes the outputs of tasks&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;compile&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;classes&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Generates the classes from source files&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;test&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;test&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Executes unit tests&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;package&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;assemble&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Creates a jar&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;verify&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;check&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Runs all tests, integration tests, quality checks, &amp;#8230;&amp;#8203;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;install&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;publishToMavenLocal&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;Gradle doesn&amp;#8217;t need a local repository, but should you need Maven interoperability, you can add the &lt;code&gt;maven-publish&lt;/code&gt; plugin to add this task&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;deploy&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;publishToMavenRepository&lt;/p&gt;&lt;/td&gt;
&lt;td class=&quot;tableblock halign-left valign-top&quot;&gt;&lt;p class=&quot;tableblock&quot;&gt;This tasks is &lt;em&gt;not&lt;/em&gt; available by default, as it depends on which type of repository you deploy to. In general you just apply the &lt;code&gt;maven-publish&lt;/code&gt; plugin to add this task&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But remember: in Gradle, tasks depend on each other. So it means that if you run a lifecycle task, &lt;em&gt;only the tasks required for that specific target are going to be executed&lt;/em&gt;. Nothing more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_see_us_at_devoxx_belgium&quot;&gt;See us at Devoxx Belgium!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you want to discover more of the differences between Gradle and Maven, come see my colleague Louis Jacomet and I during Devoxx Belgium, we&amp;#8217;re giving a &lt;a href=&quot;https://dvbe18.confinabox.com/talk/UAH-5130/Switching_to_Gradle:_maturity,_performance,_and_pleasure!&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;deep dive into Gradle&lt;/a&gt; where we&amp;#8217;re going to cover what is explained here, and much more!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Assistants vocaux et robotisation: mon point de vue</title>
      <link>https://melix.github.io/blog//2018/07/robots-vs-human.html</link>
      <pubDate>Tue, 3 Jul 2018 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2018/07/robots-vs-human.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce billet essaie de résumer une conversation que j&amp;#8217;ai eu avec mon frère, concernant les craintes autour des assistants vocaux, et, plus généralement, la robotisation. Je partage une grande partie de &lt;a href=&quot;https://www.blogdumoderateur.com/role-controverse-assistants-vocaux/&quot;&gt;son point de vue&lt;/a&gt;, mais j&amp;#8217;ai aussi de larges différences que je voulais résumer ici. C&amp;#8217;est parti !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_ok_google_crée_un_malaise&quot; class=&quot;sect0&quot;&gt;&quot;Ok Google, crée un malaise&quot;&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le week-end dernier, à l&amp;#8217;occasion d&amp;#8217;un barbecue en famille à la maison, ma moitié a, au détour d&amp;#8217;une conversation, lancé cette phrase par pur réflexe:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&quot;Ok Google, &amp;lt;question anodine&amp;gt;&quot;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Là, mon frère, Guillaume, a fait un malaise. Etendu sur le sol, pris de spasmes incontrôlables, en position foetale, il baffouillait des phrases pour la plupart inintelligibles, mais, par moments, j&amp;#8217;arrivais à comprendre des bribes comme &quot;pas eux&quot;, &quot;GDPR&quot;, ou autres &quot;Saint Qwant venez-vous en aide&quot;. Après quelques minutes, l&amp;#8217;intervention d&amp;#8217;un seau d&amp;#8217;eau et rongé par la honte de se montrer ainsi devant junior, Guillaume repris ses esprits, et commença une discussion trop courte parce qu&amp;#8217;interrompue par la nécessité autrement plus primaire de faire griller quelques saucisses.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au final, la question se résume à celle-ci: pourquoi ? De mon côté, je suis assez ouvert sur l&amp;#8217;utilisation des assistants, et je dois dire que c&amp;#8217;est quelque chose que j&amp;#8217;attendais véritablement depuis des années. De lonnngggues années. Guillaume n&amp;#8217;avait probablement rien noté jusqu&amp;#8217;ici parce que mon assistant prenait la forme d&amp;#8217;une enceinte bluetooth classique, alors qu&amp;#8217;il s&amp;#8217;agit en fait une enceinte Sony intégrant la technologie de Google. J&amp;#8217;avais choisi ce modèle principalement parce qu&amp;#8217;une des utilisations que je fais de cet assistant, probablement la plus fréquente, est de lui demander de me diffuser de la musique (via Deezer), ou la radio. La domotique, c&amp;#8217;est un peu un rêve de gosse pour moi, j&amp;#8217;adore tout piloter, par une appli, ou par la voix. Donc parmi les autres utilisations que j&amp;#8217;en fais, il y a:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;contrôler mes lumières, mon thermostat&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;contrôler ma box domotique (et donc les appareils non directement &quot;connectés&quot;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;demander des informations (météo, à quelle heure est le match de la France, &amp;#8230;&amp;#8203;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;enclencher un minuteur pour la cuisine, ajouter des rappels&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le problème, qui choque Guillaume, est que pour avoir accès à toutes ces fonctions, je partage énormément de données avec El Diablo (Google). Oui, mais j&amp;#8217;en suis conscient. Et, par ailleurs, mon compte est configuré avec une extrême précaution. Notamment, j&amp;#8217;ai complètement désactivé la personnalisation des annonces. Je garde néanmoins certaines fonctionnalités comme le traçage de ma position géographique (qui, par une occasion, m&amp;#8217;a permis de démontrer à des amis qu&amp;#8217;on était bien allé les voir au mois d&amp;#8217;Octobre :)). J&amp;#8217;ai plus de mal, en revanche, sur l&amp;#8217;historique des recherches. Mais le noeud du problème, c&amp;#8217;est qui détient les données, ce qu&amp;#8217;ils en font et en particulier avec qui ils les partagent. Pour ma part, la seule raison pour laquelle j&amp;#8217;utilise les services de Google est qu&amp;#8217;ils me permettent &lt;em&gt;techniquement&lt;/em&gt; de faire ce que je veux. Si, demain, j&amp;#8217;ai la possibilité d&amp;#8217;avoir une box locale qui m&amp;#8217;offre les mêmes capacités, y compris lorsqu&amp;#8217;invoquée via IFTTT, je signe à quatre mains. En attendant que celà existe, et j&amp;#8217;espère sincèrement que celà arrivera au plus vite, je fais des compromis, et il faut être conscient de ce que l&amp;#8217;on a a la maison.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Là où je suis moins d&amp;#8217;accord, c&amp;#8217;est la diabolisation à l&amp;#8217;extrême des assistants. Je reviendrais plus tard sur quelques raisons, mais en particulier un argument que j&amp;#8217;entends souvent, c&amp;#8217;est &quot;oui mais là tu as un micro qui écoute tout le temps chez toi et qui envoie tes données à Google&quot;. Ah, nous y voilà. Quel est le problème ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;ça écoute tout le temps ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ça envoie tes données ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ça les envoie à Google ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;qui traite des infos ?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_intention_malicieuse_ou_non&quot; class=&quot;sect0&quot;&gt;Intention malicieuse ou non ?&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;avoue que j&amp;#8217;ai du mal à comprendre les réticences ici. Probablement parce que je suis un développeur naif, mais les bugs, les amis, je suis désolé de vous l&amp;#8217;apprendre, il y en aura toujours. Donc, oui, il arrivera que votre Google Home, votre Amazon Alexa ou autre, se mette à enregistrer une conversation qu&amp;#8217;il n&amp;#8217;aurait pas du, et l&amp;#8217;envoie sur les serveurs de Google. En règle générale, on le comprend assez vite, parce que la douce voix robotique vous répondra quelque chose du genre &quot;désolé, je ne sais pas comment vous aider&quot;. Que s&amp;#8217;est-il vraiment passé ? La box a cru entendre un mot clé. Souvent, on se demande parfois pourquoi Google n&amp;#8217;offre pas la possibilité de changer ce mot clé (&quot;Ok Google&quot;, &quot;hey Google&quot;, &amp;#8230;&amp;#8203;). Je pense qu&amp;#8217;une des raisons est ce que l&amp;#8217;interprétation de ce mot clé est forcément locale. La puissance nécessaire pour reconnaitre parfaitement l&amp;#8217;expression, et son contexte de déclenchement avec le bruit, est restreinte. Donc, parfois, pas de bol, ça croit entendre &quot;Ok Google&quot;, ou, pire, ça s&amp;#8217;enclenche lorsque la pub passe à la télé. En règle générale, ça fait plutôt rire mes enfants, rien de dramatique. D&amp;#8217;autant qu&amp;#8217;on sait que ça s&amp;#8217;enclenche grâce au signal sonore &quot;attention, Google écoute&quot;. Donc, un bug, c&amp;#8217;est un bug. Ca n&amp;#8217;est pas parce que ça &lt;em&gt;peut&lt;/em&gt; envoyer des données sans votre accord que l&amp;#8217;intention derrière est malicieuse. Dois-je vous rappeler les histoires d&amp;#8217;activation à distance des webcams des Mac Book par la NSA ? On n&amp;#8217;est pas dans la même catégorie, là. Enfin, des micros qui écoutent tout le temps, vous en avez en poche depuis des années: vos téléphones mobiles. Ils font exactement la même chose, sont activables à distance, et probablement infectés de tonnes de malwares, parfois installées en usine, à des fins d&amp;#8217;espionnage gouvernemental. Si je dois me méfier de quelque chose, personnelement, c&amp;#8217;est plus de ça que de Google recevant ma discussion sur tata Simone.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Par ailleurs, une fois la conversation envoyée sur le &quot;cloud&quot; (ça fait peur, le cloud, on ne sait pas ce qui s&amp;#8217;y passe), elle est analysée. Pensez-vous que ce sont des humains qui analysent votre question et renvoie la réponse en 2s ? Non, la puissance de calcul nécessaire pour interpréter correctement votre question et titanesque. Elle nécessite des techniques avancées (TALN, statistiques, oui, vous savez, la même chose que ce gros mot &quot;big data&quot;), et l&amp;#8217;apprentissage pour l&amp;#8217;amélioration de la qualité des réponses requiert le stockage de quantités monstrueuses d&amp;#8217;information. Je ne suis pas convaincu que Google doive pour autant &lt;em&gt;stocker&lt;/em&gt; toutes les conversations, mais je conçois parfaitement qu&amp;#8217;en analysant les requêtes de millions d&amp;#8217;utilisateurs, avec des voix différentes, des accents différents et des contextes culturels différents, on est capable de faire beaucoup mieux qu&amp;#8217;en ne stockant rien et analysant localement. Le temps où il fallait patiemment passer des heures à répéter des tonnes de phrases à son logiciel de reconnaissance vocal n&amp;#8217;est pas si loin&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Donc, oui, Google va recevoir ma voix. Oui, il va l&amp;#8217;analyser et construire un profil, qu&amp;#8217;il pourra partager. Je suis au courant. Et j&amp;#8217;ai, dans la mesure du possible, restreint ces possibilités. Je serai d&amp;#8217;autant plus heureux le jour où je n&amp;#8217;aurai pas besoin de lui confier mes données. Mais l&amp;#8217;intégration, la simpliciter d&amp;#8217;utilisation, et le seul fait que ça marche, aujourd&amp;#8217;hui, est la raison de son adoption. Enfin, on dit que ça marche, mais après des mois d&amp;#8217;utilisation, il ne faut pas très longtemps pour comprendre que malgré les quantités énormes de données dont Google dispose, dans de très nombreux cas, l&amp;#8217;assistant est complètement à la ramasse. Genre, on lui demande si un match passe sur TF1, il est incapable de répondre. On lui demande &quot;quel temps va-t-il faire&quot;, il comprend &quot;température&quot;. On apprend même à reformuler nos questions pour que l&amp;#8217;assistant les comprenne. Bizarre, et frustrant. Mais, ça montre les limite de la technologie, et casse quelques mythes. En particulier, il faut se méfier des annonces autour de Google Duplex, l&amp;#8217;assistant qui prend des rendez-vous à votre place: oui, ça marche, c&amp;#8217;est bluffant, mais il est conçu pour cette tâche spécifique, et il est finalement assez simple, d&amp;#8217;après les premiers retours, de lui faire perdre le fil.&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_la_relation_homme_machine&quot; class=&quot;sect0&quot;&gt;La relation homme-machine&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Néanmoins, la conversation a dévié vers l&amp;#8217;intelligence artificielle en règle générale, et la relation qu&amp;#8217;on a avec les machines. Sur ce sujet, je suis &lt;em&gt;extrêmement&lt;/em&gt; ouvert. Je suis très introverti, et, personnellement, avoir une conversation avec une machine a un côté rassurant. Me demandez pas pourquoi, c&amp;#8217;est un fait. Je narrais aussi cette anecdote à mon frère: un de mes enfants a des difficultés à parler aux adultes. Il marmonne, ne les regarde pas dans les yeux, et met &lt;em&gt;beaucoup&lt;/em&gt; de temps à leur accorder sa confiance (mais une fois qu&amp;#8217;elle est acquise, il n&amp;#8217;y a plus de pb). Personnellement, ça ne m&amp;#8217;a jamais inquiété, j&amp;#8217;étais pareil enfant, et ça n&amp;#8217;a (je pense) pas fait de moi un être associal (j&amp;#8217;espère). Disposant de Google Home, mon fils s&amp;#8217;est naturellement mis à l&amp;#8217;utiliser lui aussi. Et ses premières expériences étaient frustrantes: n&amp;#8217;articulant pas, la machine n&amp;#8217;était pas capable de le comprendre. En quelques semaines seulement, il a progressé plus qu&amp;#8217;en plusieurs années: désormais, il articule et parle fort, y compris aux adultes (à de rares exceptions près pour ceux qui l&amp;#8217;impressionnent comme le médecin). Ce sujet en a apporté un autre: celui du fait de faire dire aux enfants &quot;merci&quot; ou &quot;s&amp;#8217;il te plait&quot; aux machines.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Guillaume est, si j&amp;#8217;ai bien compris, contre l&amp;#8217;humanisation des machines. Pour ma part, j&amp;#8217;y suis favorable, et je suis donc pour la &quot;politesse envers les machines&quot;. Fondamentalement, je pense qu&amp;#8217;une partie des craintes de Guillaume se fondent sur le fait de confier l&amp;#8217;empathie aux machines et que des algorithmes s&amp;#8217;en servent pour nous manipuler. L&amp;#8217;autre aspect est l&amp;#8217;aliénation de l&amp;#8217;homme à la machine, c&amp;#8217;est à dire apprendre à des enfants à obéir non plus à des hommes mais à des machines. Soit, c&amp;#8217;est une crainte légitime. Je suis plus cynique que celà: je doute qu&amp;#8217;une machine puisse faire pire qu&amp;#8217;un être humain. En fait, j&amp;#8217;ai plus d&amp;#8217;espoir envers les machines que je n&amp;#8217;en ai envers les êtres humains. L&amp;#8217;histoire a montré a de trop nombreuses occasions que l&amp;#8217;empathie n&amp;#8217;est pas l&amp;#8217;apparat de tout le monde, bien au contraire. L&amp;#8217;utilisation des biais cognitifs à des fins de manipulation (vente, politique, abus de confiance), ça n&amp;#8217;a rien de nouveau. Est-ce qu&amp;#8217;il faut craindre que les algorithmes fassent de même ? Oui. Serait-ce pire qu&amp;#8217;avec des humains ? J&amp;#8217;en doute, bien au contraire. L&amp;#8217;imagination perverse des hommes n&amp;#8217;est plus à démontrer. Leur intolérance non plus.&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_suis_je_humain&quot; class=&quot;sect0&quot;&gt;Suis-je humain ?&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;ai grandi avec Star Trek.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette série est probablement celle qui a influencé une grande partie de ma pensée. Déja dans Star Trek TOS, l&amp;#8217;ordinateur et la domotique étaient au coeur de la relation homme-machine. La machine était naturellement intégrée, un personnage &quot;vivant&quot; en quelque sorte. Puis, arriva Star Trek The Next Generation, avec des personnages encore plus humanistes, mais un personnage en particulier, Data, change la donne: un Androide dont la seule quête était de devenir humain. Un membre à part entière de l&amp;#8217;équipage. Un &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Measure_of_a_Man_%28Star_Trek:_The_Next_Generation%29&quot;&gt;épisode en particulier traite spécifiquement du sujet du droit des robots&lt;/a&gt;: Data devait-il être considéré comme une machine ou un humain ? Un scientifique a-t-il le droit de le démembrer pour l&amp;#8217;étudier sur le seul prétexte qu&amp;#8217;il s&amp;#8217;agit d&amp;#8217;une machine ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;adore cette série pour celà: son humanisme, sa capacité à rechercher ce qu&amp;#8217;il y a de meilleur chez l&amp;#8217;homme, et son ouverture en général. Subtilement mais sûrement, les sujets sensibles sur le racisme, le transhumanisme, l&amp;#8217;homosexualité y sont traités.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Je fais donc partie de ceux qui préfèrent avoir une &quot;conversation&quot; avec une machine polie, lui répondre &quot;merci&quot;, tout en sachant qu&amp;#8217;il ne s&amp;#8217;agit que d&amp;#8217;une machine, plutôt de de causer à un con&amp;#8230;&amp;#8203; raciste, homophobe, ou plus fréquemment un télécommercial essayant toutes les techniques possibles pour me vendre ses panneaux solaires sachant pertinnement que je veux terminer ma conversation avec lui. Je pense que la politesse, le &quot;savoir vivre&quot;, procure une certaine satisfaction, une relaxation, qui est un concept totallement orthogonal avec le sujet (l&amp;#8217;homme ou la machine). Il n&amp;#8217;est pas surprenant pour moi que des autistes s&amp;#8217;ouvrent plus facilement avec la présence d&amp;#8217;un animal (chien, chat, peu importe), ou que certaines expériences montrent des enfants &lt;a href=&quot;https://www.topsante.com/medecine/psycho/autisme/des-robots-une-aide-pour-les-enfants-autistes-63967&quot;&gt;faisant des progrès en parlant à des robots&lt;/a&gt;. L&amp;#8217;interaction, la socialisation est importante. Et si le robot est meilleur que l&amp;#8217;homme sur ce sujet, on doit s&amp;#8217;en réjouir ! L&amp;#8217;homme a toujours cherché à créer des choses à son image (ça ne vous rapelle rien ?) et il se trouve que notre cerveau est conçu pour reconnaitre la douleur de l&amp;#8217;autre (empathie) et y réagir. Je préfère donc 100 fois, que dis-je, 1000 fois un homme poli envers un robot, qu&amp;#8217;un homme traitant une autre personne comme une machine. C&amp;#8217;est peut-être naif, mais j&amp;#8217;ai espoir qu&amp;#8217;en apprenant à des enfants à être polis envers des machines, ils apprendront d&amp;#8217;autant plus à l&amp;#8217;être envers les autres, et qu&amp;#8217;on effacera une partie de ce mal, qui est la disparition à l&amp;#8217;échelle de la société de l&amp;#8217;empathie. Et mon rêve de gosse, c&amp;#8217;est de voir un Data émerger. Montrer qu&amp;#8217;avec suffisamment de puissance, une machine puisse prendre son autonomie. On en est encore loin, mais, on réduit déja ce qui est &quot;visible&quot; entre homme et machine. Si je ne suis pas capable de faire la différence entre un homme et une machine dans une conversation, qu&amp;#8217;est-ce que celà dit de moi ? Qu&amp;#8217;est-ce que celà dit de la machine ? Et si, nous mêmes, n&amp;#8217;étions finalement qu&amp;#8217;une machine un peu sophistiquée, issue de l&amp;#8217;évolution. Une machine douée de pensée et de sentiments, mais une machine quand même.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Parlons Gradle : Episode 1</title>
      <link>https://melix.github.io/blog//2017/10/parlons-gradle.html</link>
      <pubDate>Mon, 30 Oct 2017 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2017/10/parlons-gradle.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Suite à de nombreuses discussions via Twitter, j&amp;#8217;ai souhaité organiser des discussions en ligne pour que nous puissions parler de Gradle. Le premier épisode aura lieu mercredi prochain, notez la date !&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align:center; color:red; font-size: 2em&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;LE MERCREDI 6 DECEMBRE , à 17h GMT+1 (Paris)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La rencontre se fera via Google Hangouts. Si vous êtes intéressés, envoyez-moi un mail (cedric -at- gradle -point- com) ou un &lt;a href=&quot;https://twitter.com/CedricChampeau&quot;&gt;tweet&lt;/a&gt; avec votre email pour que je vous envoie une invitation. Pour des raisons pratiques, elle se fera en français uniquement !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_de_quoi_va_t_on_parler&quot;&gt;De quoi va-t-on parler ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L&amp;#8217;objectif pour moi est de récolter votre ressenti sur Gradle, son utilisation, vos problèmes au quotidien, la documentation, les exemples, mais aussi ce que vous aimez, votre utilisation, &amp;#8230;&amp;#8203; Bref, votre expérience utilisateur. Certains sont encore convaincus que Maven est supérieur, ce qui, de mon point de vue, reste un mystère, et j&amp;#8217;ai donc besoin d&amp;#8217;entendre votre feedback pour savoir comment corriger (si nous n&amp;#8217;avons pas encore entrepris de démarche dans ce sens).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, il s&amp;#8217;agira d&amp;#8217;une discussion ouverte, d&amp;#8217;environ 1h. Bien entendu nous pourrons parler du futur de Gradle si nous avons le temps.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au plaisir de vous voir !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Pourquoi je soutiens Benoît Hamon</title>
      <link>https://melix.github.io/blog//2017/03/soutien-hamon.html</link>
      <pubDate>Wed, 1 Mar 2017 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2017/03/soutien-hamon.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette élection présidentielle est unique. A bien des égards. La première raison, qui m&amp;#8217;est insupportable, est que pour la première fois, une candidate FN, Marine Le Pen, est en position de gagner cette élection: un mirroir de ce qui se passe à l&amp;#8217;échelle mondiale, avec un repli sur soi et une montée inquiétante du populisme. La seconde, parce qu&amp;#8217;évidemment jamais le rejet des politiques en place n&amp;#8217;aura été aussi important. Pour autant, c&amp;#8217;est aussi une opportunité, pour une fois, de changer radicalement de société. Les choix qui s&amp;#8217;offrent à nous sont particulièrement clairs: une droite extrêmement dure avec Fillon et Le Pen, ou une gauche sans compromis avec Hamon ou Mélenchon. Sans oublier, bien sûr, l&amp;#8217;outsider désormais favori Macron, dont je ne sais toujours pas s&amp;#8217;il a des convictions ou s&amp;#8217;il est simplement le reflet de la nature, qui a horreur du vide (je ne sais pas où voter, allons là où tout le monde semble se rallier).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour ma part, je vote par conviction. J&amp;#8217;aurais bientôt 38 ans, et je dois dire que jamais, je n&amp;#8217;ai été si proche des idées d&amp;#8217;un candidat. Je le suis depuis plusieurs mois, bien avant la primaire, et mes amis proches savent que je leur en parlais et que je croyais en sa victoire. Dans ce billet, je veux vous donner quelques pistes pour lesquelles je soutiens Benoît Hamon, et pourquoi je vous invite à le rejoindre.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Note&lt;/div&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
A mes lecteurs habituels, ce billet n&amp;#8217;a rien à voir avec mes interventions techniques. Libre à vous de l&amp;#8217;ignorer. Par ailleurs, je souligne évidemment que ce qui est écrit ici n&amp;#8217;engage que moi, et personne d&amp;#8217;autre que moi.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_le_revenu_universel&quot;&gt;Le revenu universel&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Commençons par le revenu universel, parce qu&amp;#8217;il est le plus clivant. Même pendant la primaire des gauches, j&amp;#8217;ai entendu des absurdités incroyables à son sujet, ou des questions très orientées des journalites simplement destinées à décridibiliser cette proposition. Pourtant, c&amp;#8217;est une idée neuve, défendue par de nombreux économistes, &lt;a href=&quot;https://www.sudouest.fr/2017/01/25/dix-economistes-defendent-le-revenu-universel-de-Benoît-hamon-3137718-705.php&quot;&gt;de droite comme de gauche&lt;/a&gt;, ainsi que d&amp;#8217;éminents chefs d&amp;#8217;entreprise, tels &lt;a href=&quot;https://www.numerama.com/politique/232346-elon-musk-juge-le-revenu-de-base-necessaire-face-aux-progres-de-la-robotique.html&quot;&gt;Elon Musk, le fondateur Tesla, Space X, devenu richissime avec la revente de PayPal&lt;/a&gt;, &amp;#8230;&amp;#8203; Pas spécialement un exemple de ratage. Rappelons son principe de base: donner, à chaque citoyen, un revenu identique (dont le montant varie selon les propositions), universel, indépendemment de ses resources, à compter de sa majorité. A droite, on &lt;a href=&quot;https://www.liberation.fr/debats/2017/02/06/non-le-revenu-universel-ne-decourage-pas-le-travail_1546717&quot;&gt;crie alors à l&amp;#8217;assistanat&lt;/a&gt;. A gauche, on hurle qu&amp;#8217;il ne faut pas donner aux riches qui ont déja bien assez.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais le monde change. Le travail change. Quiconque vous dit le contraire est soit aveuglé, soit vous ment. Je travaille dans l&amp;#8217;informatique, et par mon activité professionnelle qui m&amp;#8217;amène à rencontrer de nombreux développeurs du monde entier, je pense être assez bien placé pour voir que ce je développe, ce qui arrive, est une nouvelle révolution industrielle (mais pas seulement, les services sont aussi touchés).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En France, vous aurez déja remarqué que les caissières se font moins nombreuses, qu&amp;#8217;il n&amp;#8217;y a plus personne aux péages, que le métro n&amp;#8217;a plus de conducteur, qu&amp;#8217;on nous vend du pain frais dans un distributeur&amp;#8230;&amp;#8203; Mais nous sommes très en retard.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;En Chine, où sont fabriqués nos précieux smartphones, les monstrueuses usines employant des dizaines de milliers d&amp;#8217;ouvriers ont déja entamé leur migration vers une &lt;a href=&quot;https://alltrends.over-blog.net/2017/02/une-entreprise-remplace-90-de-ses-employes-par-des-robots.html&quot;&gt;robotisation intégrale&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Singapour et aux Etats-Unis, les &lt;a href=&quot;https://www.lemonde.fr/economie/article/2016/08/25/les-premiers-taxis-sans-chauffeur-roulent-a-singapour_4988089_3234.html&quot;&gt;taxis sont remplacés par les voitures autonomes&lt;/a&gt; (notez l&amp;#8217;ironie, au passage: pour un Fillon ou un Macron dont le modèle est &lt;a href=&quot;https://www.streetpress.com/sujet/1488276642-coursier-velo-se-fait-virer&quot;&gt;l&amp;#8217;Uberisation de la société, l&amp;#8217;auto-entreprenariat&lt;/a&gt;, là où il est clair depuis des mois que le but de cette même entreprise est le 0 salarié&amp;#8230;&amp;#8203;). Des &lt;a href=&quot;https://thegoodlife.thegoodhub.com/2016/05/19/otto-camion-se-conduit-seul/&quot;&gt;poids lours conduisent tout seuls sur des centaines de kilomètres&lt;/a&gt;. &lt;a href=&quot;https://www.lemonde.fr/technologies/article/2013/12/02/des-paquets-livres-par-drones-d-ici-cinq-ans_3523489_651865.html&quot;&gt;Amazon livre par drones&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Au Japon, ce sont mêmes des &lt;a href=&quot;https://www.numerama.com/tech/221747-une-i-a-remplace-34-employes-dune-assurance-au-japon.html&quot;&gt;employés d&amp;#8217;une assurance qui sont remplacés par une intelligence artificielle&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Watson, l&amp;#8217;IA développée par IBM, a déja &lt;a href=&quot;https://www.letemps.ch/sciences/2016/09/22/un-outil-diagnostic-medical-nomme-watson&quot;&gt;diagnostiqué une leucémie que les médecins avaient ratée&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Un &lt;a href=&quot;https://www.theguardian.com/technology/video/2017/feb/28/meet-handle-the-two-wheeled-four-legged-hybrid-robot-video&quot;&gt;robot pourra bientôt transporter des charges lourdes à notre place&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Quoi qu&amp;#8217;on en pense, à moyen terme, la &lt;strong&gt;révolution robotique&lt;/strong&gt; est en marche, et c&amp;#8217;est une bonne chose. Bien sûr, on ne parle pas d&amp;#8217;un remplacement à court terme. Tout celà est progressif. Des métiers vont disparaître, d&amp;#8217;autres se transformer, d&amp;#8217;autres encore vont apparaître, mais il est indéniable que le volume de travail global disponible à l&amp;#8217;humain fond comme neige : nous sommes toujours plus nombreux sur la planète, le &lt;a href=&quot;https://data.oecd.org/chart/4KKb&quot;&gt;PIB augmente, pour autant le volume d&amp;#8217;heures travaillées évolue peu&lt;/a&gt;. L&amp;#8217;étude la plus optimiste de l&amp;#8217;OCDE indique que &lt;a href=&quot;https://www.lemonde.fr/economie/article/2016/05/20/pour-l-ocde-9-des-emplois-sont-menaces-par-les-robots_4923165_3234.html&quot;&gt;près de 10% des emplois sont menacés à court terme&lt;/a&gt;. Une autre étude parle elle de &lt;a href=&quot;https://www.francetvinfo.fr/replay-radio/nouveau-monde/les-robots-le-chomage-et-les-emplois-de-2030_1777669.html&quot;&gt;50% des emplois remplaçables par des robots à l&amp;#8217;horizon 2030&lt;/a&gt;. Lorsqu&amp;#8217;on choisit une politique, il ne faut pas penser à court terme, mais à nos enfants. Même s&amp;#8217;il est idiot d&amp;#8217;affirmer que le travail va disparaitre (qui peut sérieusement le croire ?), il se transforme, et il faut embrasser cette transformation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J&amp;#8217;en suis convaincu, les politiques qui ignorent ces changements vivent dans un monde qui n&amp;#8217;existe plus: ils achètent leur pain au chocolat à 10 centimes, font leurs courses chez Prisunic et rêvent de payer leurs assistants parlementaires européens en Francs. Ignorer les changements du travail, c&amp;#8217;est ignorer l&amp;#8217;avenir, s&amp;#8217;aliéner à ceux qui embrassent ce changement, perdre notre souveraineté. Au lieu de combattre ce futur, il faut au contraire s&amp;#8217;y préparer et repenser notre société autour de ces changements. L&amp;#8217;automatisation, la robotisation, n&amp;#8217;engendre pas de perte de valeur: celle-ci est toujours présente, les prix ne baissent en général pas: la productivité augmente et on réduit la pénibilité. Deux choix de société s&amp;#8217;engagent alors: profiter de cette amélioration pour vivre mieux, ou une fuite en avant productiviste. A ce sujet, je conseille la lecture de &lt;a href=&quot;https://crew.co/blog/why-you-shouldnt-work-set-hours/&quot;&gt;ce billet&lt;/a&gt; à mes lecteurs anglophones: ou comment le temps de travail est fonction des évolutions de la société, pas une constante.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ceci appelle à une révolution fiscale: là où aujourd&amp;#8217;hui on taxe le travail, il faudra demain &lt;a href=&quot;https://www.lci.fr/elections/quelle-est-donc-cette-taxe-robots-proposee-par-Benoît-hamon-qui-seduit-jusqu-a-bill-gates-2026781.html&quot;&gt;taxer les robots&lt;/a&gt;, comme &lt;a href=&quot;https://fortune.com/2017/02/18/bill-gates-robot-taxes-automation/&quot;&gt;le propose aussi Bill Gates&lt;/a&gt;. Si ce terme peut faire sourire, il cache en réalité de nombreuses ramifications: évasion fiscale en particulier. Quelle pire injustice que de voir nos petites entreprises crouler sous des 30% de taxes, lorsque les grandes entreprises étrangères qu&amp;#8217;on utilise tous (smartphones, distribution), qui robotisent, automatisent et n&amp;#8217;embauchent quasiment pas, placent &quot;leur&quot; argent dans des paradis fiscaux et ne paient pas d&amp;#8217;impôts, grâce à des montages financiers complexes avec la complicité de nos cabinets comptables ? Ne marchons nous pas sur la tête ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, oui, on peut continuer à sourire, dire qu&amp;#8217;il faut baisser les charges pour les entreprises et les salariés (ce qui serait une bonne chose), mais si on n&amp;#8217;embrasse pas cette virtualisation de l&amp;#8217;économie, on ne fait que réduire l&amp;#8217;assiète des cotisations, et se ruiner un peu plus.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors que vient faire le revenu universel là dedans ? Il permet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;de mettre fin à la grande pauvreté, en particulier en remplaçant le RSA, belle idée mais tellement complexe que nombreux sont ceux qui y ont droit et ne le demandent pas. Par ailleurs, si le revenu est effectivement universel, l&amp;#8217;argument de la fraude aux aides ne tient plus: tout le monde y a droit, point.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de favoriser le temps partiel. Dans certains Etats, comme les &lt;a href=&quot;https://www.lemonde.fr/economie/article/2016/02/03/aux-pays-bas-on-travaille-en-moyenne-30-heures-par-semaine_4858496_3234.html&quot;&gt;Pays-Bas, c&amp;#8217;est déja la norme, y compris chez les hommes&lt;/a&gt;, réduisant ainsi les inégalités homme-femme. Le PIB de ce pays n&amp;#8217;a pas chuté, les employés n&amp;#8217;en sont que plus heureux.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de maintenir l&amp;#8217;emploi. Des histoires d&amp;#8217;agriculteurs qui travaillent comme des fous et ne s&amp;#8217;en sortent plus, on en lit tous les jours. Avec &lt;a href=&quot;https://twitter.com/Benoîthamon/status/836905767571697664&quot;&gt;350€&lt;/a&gt; par mois, franchement, vous resteriez? Je connais personnellement l&amp;#8217;un d&amp;#8217;entre eux qui a fini par abandonner. Avec le revenu universel, on permet à ces travailleurs pauvres de rester en poste.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de choisir de travailler plutôt que rester à la maison. Je ne sais pas pour vous, mais le nombre de fois où j&amp;#8217;ai entendu quelqu&amp;#8217;un me dire &quot;avec mes frais de garde et de transport, ça me revient plus cher d&amp;#8217;aller travailler que de rester chez moi&quot;. Pas franchement encourageant, non?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de valoriser des activités non commerciales mais importantes pour la société : travail associatif, aides à la personne, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;de partager le travail: à coût égal pour une entreprise, il sera possible de prendre 2 salariés au lieu d&amp;#8217;un seul, et ainsi donc réduire les risques de TMS (pour les travaux manuels) ou burn-outs : il existe une limite physique à la productivité.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En revanche, le RU ne rend pas les riches plus riches. C&amp;#8217;est un &lt;strong&gt;revenu&lt;/strong&gt;. En conséquence, il est imposable. Il s&amp;#8217;ajoute donc à votre salaire et suivant vos revenus, vous devrez payer ou non des impôts dessus. Il est donc incorrect de dire que ça coute 400 milliards (ou plus). En pratique, il coûte sensiblement moins, en particulier si son implémentation se fait &lt;em&gt;via&lt;/em&gt; un crédit d&amp;#8217;impôt. La justice fiscale est maintenue. Le soumettre à conditions de ressources, c&amp;#8217;est augmenter son coût intrinsèque (gestion, contrôles) ou inciter à la fraude pour quelque chose qui ne change au final rien. Quant à l&amp;#8217;argument de l&amp;#8217;incitation à l&amp;#8217;oisiveté, il me fait doucement sourire. A tous ceux qui me l&amp;#8217;ont avancé, je leur ai posé une question simple: si on vous donnait 600€ par mois, est-ce que vous quitteriez votre boulot ? Est-ce que ça vous suffirait ? Je pense que je n&amp;#8217;ai pas besoin de vous donner les réponses&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, certains taxent cette proposition d&amp;#8217;irréaliste, utopique, irréalisable et j&amp;#8217;en passe. Ils doutent de sa crédibilité. Mais que proposent-ils ? Toujours les mêmes solutions ! Réduire les charges des entreprises (merci Fillon pour son exonération sur les bas salaires, effet d&amp;#8217;aubaine pour n&amp;#8217;augmenter personne, alors que la répartition de la valeur n&amp;#8217;a &lt;a href=&quot;https://www.inegalites.fr/spip.php?page=article&amp;amp;id_article=1156&quot;&gt;jamais été aussi dévaforable aux pauvres et classes moyennes&lt;/a&gt;). Augmenter la TVA (belle justice fiscale !). Qui se souvient, à l&amp;#8217;inverse, de la baisse de la TVA pour la restauration, en l&amp;#8217;échange, soit disant, d&amp;#8217;emplois et de baisses de prix ? Qui se souvient encore du badge &lt;a href=&quot;https://www.lemonde.fr/emploi/article/2014/09/24/pierre-gattaz-oui-il-est-possible-de-creer-un-million-d-emplois_4493160_1698637.html&quot;&gt;1 million d&amp;#8217;emplois de Pierre Gattaz&lt;/a&gt; en l&amp;#8217;échange du pacte de compétitivité ? Travailler plus, en défiscalisant les heures supplémentaires, encore une mesure populaire, mais qui ne crée pas d&amp;#8217;emplois (la vraie injustice), et n&amp;#8217;est qu&amp;#8217;un pansement sur une jambe de bois: est-ce que cette politique a déja une seule fois marché ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Autre question: qui peut encore croire que repousser l&amp;#8217;âge de la retraite est une solution, alors même que les seniors sont &lt;a href=&quot;https://www.lemonde.fr/societe/article/2011/07/29/chomage-les-seniors-sont-indesirables-dans-les-entreprises_1553945_3224.html&quot;&gt;&quot;trop vieux pour travailler&quot; dès 50 ans&lt;/a&gt; ? Je ne suis fondamentalement pas contre repousser l&amp;#8217;âge de la retraite (qui finalemement va de pair avec l&amp;#8217;augmentation de l&amp;#8217;espérance de vie), mais faire ça alors même que nos seniors sont au chômage n&amp;#8217;a aucun sens. Il faut d&amp;#8217;abord revaloriser l&amp;#8217;expérience, changer notre vision. Comment peut-on imaginer créer des emplois en faisant travailler plus ceux qui ont la chance d&amp;#8217;en avoir un, &lt;a href=&quot;https://www.francetvinfo.fr/replay-radio/on-s-y-emploie-de-philippe-duport/l-inquietante-progression-des-troubles-musculo-squelettiques_1790187.html&quot;&gt;quitte à les briser&lt;/a&gt; ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;60 milliards ont été engloutis dans le CICE, pour quel résultat ? Autre solution classique, se reposer sur une croissance, dont les prévisions sont systématiquement revues à la baisse, et donc les conséquences sur notre planète commencent sérieusement à se faire sentir ? Ou faciliter le licenciement, en croyant dogmatiquement que ça facilite l&amp;#8217;embauche ? Ce dont ont besoin les entreprises, ce n&amp;#8217;est pas de pouvoir licencier. Personne ne veut licencier par plaisir. Ce qu&amp;#8217;il faut, c&amp;#8217;est de la stabilité. Connaitre les règles du jeu à l&amp;#8217;avance, et qu&amp;#8217;elles ne changent pas tous les jours, ainsi qu&amp;#8217;une juste concurrence : que les petites paient les mêmes impôts que les grosses, et que les différences de législation entre partenaires commerciaux ne soient pas un frein aux entreprises locales (donc, un protectionnisme &lt;em&gt;raisonné&lt;/em&gt;). Alors, dites-moi, qui est irréaliste et utopique ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, on va nous parler de &quot;valeur travail&quot;. Ou la réalisation par le travail. Est-ce là une valeur que je veux transmettre à mes enfants ? Non. Si le travail est important, il ne doit pas être le critère de réalisation, en particulier dans une société ou le travail se raréfie. C&amp;#8217;en est de plus insultant pour tous ceux qui ne trouvent pas d&amp;#8217;emploi, ou pour ceux qui s&amp;#8217;investissent autrement (associations, sportifs, artistes) et contribuent à la grandeur de notre pays. Ce que j&amp;#8217;enseigne à mes enfants, c&amp;#8217;est qu&amp;#8217;il faut se donner à fond et ne pas se fermer de portes. Je leur apprends la tolérance. Je leur apprends à apprécier la chance qu&amp;#8217;ils ont par rapport à d&amp;#8217;autres. Je leur apprends que l&amp;#8217;effort est récompensé, mais que parfois, la vie est injuste. Travailler, oui, mais choisir. Le choix, la liberté sont la clé de la réalisation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et d&amp;#8217;avenir, parlons-en.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_révolution_écologique&quot;&gt;La révolution écologique&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Lorsqu&amp;#8217;on parle de révolution industrielle, on ne peut ignorer la transition écologique à mener, et son potentiel énorme en termes d&amp;#8217;emplois. La France a trop longtemps dirigé tous ses crédits vers le nucléaire, en en ignorant volontairement le coût réel (démantèlement, notamment) et son impact sur l&amp;#8217;environnement (bien sûr, un accident n&amp;#8217;arrive jamais). Mais le plus gros mensonge, c&amp;#8217;est encore notre fameuse indépendence énergétique. Faut-il rappeler d&amp;#8217;où vient le combustible si précieux dont nous avons besoin ? Pour autant, il ne faut pas être naif: sortir du nucléaire prend du temps, mais c&amp;#8217;est aussi une énorme opportunité. En échelonnant dans le temps, comme le propose Benoît Hamon, on permet de maintenir notre capacité de production, tout en ouvrant de nouvelles voies de développement, créant des emplois. La catastrophe serait de faire comme en Allemagne, où toutes les centrales ont été remplacées par des centrales à charbon, dont le bilan carbone est redoutable&amp;#8230;&amp;#8203; Cette &lt;a href=&quot;https://www.electricitymap.org/&quot;&gt;carte interactive&lt;/a&gt; est plus que parlante&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mais l&amp;#8217;écologie ne se limite pas au nucléaire. L&amp;#8217;opposition ferme de Benoît Hamon aux perturbateurs endocriniens est un autre exemple de ce que j&amp;#8217;aime dans sa vision: il est temps d&amp;#8217;en finir avec la dictature de la croissance, qui détruit notre environnement et provoque de graves maladies. Penser que je puisse être responsable du futur cancer de mes enfants m&amp;#8217;est juste impossible: si je peux faire quelque chose aujourd&amp;#8217;hui, quitte à sacrifier un peu de confort (je suis le premier à changer de smartphone tous les 3/4 ans, mais en ai-je vraiment besoin ?), faisons-le. Il existe des solutions: circuits courts, production raisonnée, retour à une agriculture prenant en compte les spécificités régionales, réduction de notre consommation de viande, &amp;#8230;&amp;#8203; Nous devons aussi nous responsabiliser en tant que consommateurs: acheter toujours moins cher, c&amp;#8217;est inciter à la baisse des salaires ou à la délocalisation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_république&quot;&gt;La République&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un des derniers points que je souhaite discuter ici est ma vision de la République. Tout d&amp;#8217;abord, je souhaite le retour au septennat. Je pense que le passage au quinquénat a été une catastrophe, contribuant à la peopolisation de la politique: on ne cherche plus à faire un projet, on parle tout de suite de la prochaine élection. Même si je n&amp;#8217;ai pas d&amp;#8217;idée précise de ce que doit être la prochaine République, il me semble clair que celle-ci est à bout de souffle. Conçue pour le Général de Gaulle, l&amp;#8217;homme providentiel. Je pense qu&amp;#8217;il faut revoir le rôle de Président, et qu&amp;#8217;il ne soit plus qu&amp;#8217;un garant de nos institutions. Pour celà, il nous faut une assemblée consistuante. Benoît Hamon n&amp;#8217;en parle pas spécialemement, et c&amp;#8217;est peut-être un des points où je suis plus en accord avec un Mélenchon que lui: il faut bien des points de désaccord. En particulier, je trouve l&amp;#8217;idée du 49-3 citoyen avec seulement 1% du corps électoral potentiellement dangereuse : la Manif pour Tous aurait pu bloquer le mariage homosexuel (oui, je suis de ceux qui pensent que donner des droits égaux à tous les citoyens n&amp;#8217;est pas supprimer vos propres droits), ou, du temps de Mitterand, je doute que la peine de mort aurait pu être abolie. En clair, je suis plutôt pour une proportionnelle intégrale, répondant à une crise de représentativité qu&amp;#8217;entretient élégamment le FN. Mais je suis aussi surtout pour la &lt;a href=&quot;https://fr.wikipedia.org/wiki/Tirage_au_sort_en_politique#Stochocratie&quot;&gt;stochocratie&lt;/a&gt;, où le fait de tirer au sort des représentants qui, eux, éliront ceux qui nous gouvernent.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_laïcité_et_peur_de_lautre&quot;&gt;Laïcité et peur de l&amp;#8217;autre&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Une de mes plus grandes désillusions de l&amp;#8217;ère Hollande. C&amp;#8217;est là que le Parti Socialiste m&amp;#8217;a perdu. J&amp;#8217;ai été affligé par la Loi Renseignement. Non seulement elle est liberticide, mais elle est aussi dangereuse pour nos entreprises, réduisant considérablement les sécurités et garanties qu&amp;#8217;elles peuvent mettre en place pour leurs clients. Mais le plus grave, le divorce, ce fut la déchéance de nationalité. Sous prétexte de protéger nos concitoyens, nous créons deux catégories de personnes, ce qui est le contraire même des fondements de notre République. Plus encore, une trahison des valeurs de gauche. Aux élections qui ont suivi, pour la première fois de ma vie, je n&amp;#8217;ai pas voté PS. Fort heureusement, cette mesure n&amp;#8217;est jamais passé, j&amp;#8217;aurais eu honte, franchement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En ce qui concerne le débat sur la laïcité, là encore, je suis à 100% derrière la position de Benoît Hamon: la loi 1901 et rien que la loi 1901. En clair, il s&amp;#8217;agit de respecter la liberté de culte. Et respecter &lt;em&gt;toutes&lt;/em&gt; les religions. Point. Il faut être sacrément culotté (ou aigri), pour dire &quot;Benoît Hamon est en résonance avec une frange islamo-gauchiste&quot;. Malek Boutih, je vous le dis sincèrement, cest propos sont une honte pour la gauche. Les simples sous-entendus de cette phrase me dégoutent. Pire, vous avez donné des arguments à l&amp;#8217;extrème droite, que nous combattons de tout notre coeur. C&amp;#8217;est indigne et tellement typique de cette gauche archaïque (un paradoxe quand vous vous qualifiez de progressiste) et loin de ses valeurs. Après de telles sorties, ne soyez plus surpris que les gens votent FN et vous bottent les fesses aux élections.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Non, je crois aux valeurs humaines. Le FN tente de nous faire croire que 2000 migrants sont responsables du chômage en France, par pitié, non. Pire encore, les migrants violent nos femmes et mangent nos enfants. Et ils n&amp;#8217;avaient qu&amp;#8217;à &lt;a href=&quot;https://s2.qwant.com/thumbr/0x0/d/4/f17a15e2d5fe46ad9f63b25011b969/b_1_q_0_p_0.jpg?u=http%3A%2F%2Fd.ibtimes.co.uk%2Fen%2Ffull%2F1410255%2Faleppo-syria.jpg&amp;amp;q=0&amp;amp;b=1&amp;amp;p=0&amp;amp;a=1&quot;&gt;rester chez eux&lt;/a&gt;, ou &lt;a href=&quot;https://www.bfmtv.com/international/migrations-l-europe-sous-le-choc-apres-la-photo-d-un-enfant-mort-noye-911785.html&quot;&gt;apprendre à nager&lt;/a&gt;. Nom d&amp;#8217;un chien, où est passé le coeur de la France ? Doit-on laisser mourrir tous ces gens, les suspecter des pires crimes, ou être à la hauteur de notre histoire, nous, le pays des Droits de l&amp;#8217;Homme ? Se dire que l&amp;#8217;allemagne accueille des millions de migrants dans le même temps où l&amp;#8217;on fait des procès à &lt;a href=&quot;https://www.francetvinfo.fr/monde/europe/migrants/aide-aux-migrants-cedric-herrou-le-passeur-condamne_2056739.html&quot;&gt;Cédric Hérrou&lt;/a&gt;. Dois-je vous rappeler ce que la stigmatisation nous a apporté voici 80 ans ? Ce monde tourne sur la tête&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_les_cas_macron_mélenchon&quot;&gt;Les cas Macron / Mélenchon&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour terminer, parlons rapidement d&amp;#8217;Emmanuel Macron et Jean-Luc Mélenchon. A la lecture de ce billet, certains peuvent se dire que je pourrais choisir Mélenchon. C&amp;#8217;est vrai, lui et Hamon partagent beaucoup d&amp;#8217;idées, tout comme les Verts et à ce titre je suis dépité qu&amp;#8217;un accord entre les 3 n&amp;#8217;ait pas eu lieu. C&amp;#8217;était, à mon humble avis, une opportunité unique pour la gauche compte-tenu de la conjecture actuelle. Je pense, pour ma part, que Benoît Hamon a véritablement compris la transition économique qui nous attend et a une personnalité moins clivante. Les solutions de repli sur soi ne fonctionneront pas. Pas plus que les solutions de Macron, qui reste une énigme. Ses discours sont d&amp;#8217;une platitude déconcertante, ses solutions en matière d&amp;#8217;économie sont peu ou prou les mêmes que celles de Fillon (libéralisation à outrance du marché du travail), et pourtant&amp;#8230;&amp;#8203; il monte, il monte&amp;#8230;&amp;#8203; Le ralliement de François Bayrou, celui là même qui disait, il y a quelques semaines, que &lt;a href=&quot;https://www.lefigaro.fr/elections/presidentielles/2017/02/22/35003-20170222ARTFIG00291-avant-de-le-soutenir-bayrou-attaquait-durement-macron.php&quot;&gt;Macron était piloté par les banquiers&lt;/a&gt; (ce qui est toujours possible puisqu&amp;#8217;il refuse d&amp;#8217;indiquer qui le finance)&amp;#8230;&amp;#8203; Je peux me tromper, mais je ne crois pas non plus à la fin du clivage droite-gauche. Nos idées sont différentes. Nos visions de la société sont différentes. Progresser, c&amp;#8217;est choisir une vision, et y aller. Faire cohabiter des idées si différentes au sein d&amp;#8217;un même gouvernement ne peut conduire qu&amp;#8217;à prendre de &quot;petites&quot; décisions ne frustrant personne. Soyez rassurés, cependant, je ne mets pas Emmanuel Macron au même niveau que François Fillon ou Marine Le Pen&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En conclusion, je ne suis pas crédule non plus, tout ceci n&amp;#8217;est pas réalisable en un jour et c&amp;#8217;est pour celà je j&amp;#8217;aime l&amp;#8217;approche de Benoît Hamon: &lt;strong&gt;jamais&lt;/strong&gt; il ne s&amp;#8217;est présenté comme le candidat providentiel, qui a la réponse à tout. Il faut laisser le temps à une politique de se mettre en place (d&amp;#8217;où le septennat). Hamon est un homme qui a une vision, il a travaillé ses dossiers, mais c&amp;#8217;est aussi un &lt;a href=&quot;https://www.Benoîthamon2017.fr/2017/02/22/rejoignez-le-conseil-citoyen/&quot;&gt;team player&lt;/a&gt;. Toutes ses mesures sont réfléchies, travaillées, et vont dans le sens d&amp;#8217;un projet à long terme: un avenir désirable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La société que l&amp;#8217;on souhaite pour nos enfants. C&amp;#8217;est à eux que je pense en le choisissant. Ce dont ils ont besoin, c&amp;#8217;est d&amp;#8217;espoir. Je ne veux pas qu&amp;#8217;ils grandissent dans ce monde qu&amp;#8217;on nous promet:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.marianne.net/societe/auchan-city-de-tourcoing-apres-la-fausse-couche-d-une-caissiere-les-inquietants-recits-de&quot; class=&quot;bare&quot;&gt;https://www.marianne.net/societe/auchan-city-de-tourcoing-apres-la-fausse-couche-d-une-caissiere-les-inquietants-recits-de&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.streetpress.com/sujet/1488276642-coursier-velo-se-fait-virer&quot; class=&quot;bare&quot;&gt;https://www.streetpress.com/sujet/1488276642-coursier-velo-se-fait-virer&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bfmtv.com/societe/vaucluse-suicide-d-un-agriculteur-dont-l-exploitation-etait-en-difficulte-963138.html&quot; class=&quot;bare&quot;&gt;https://www.bfmtv.com/societe/vaucluse-suicide-d-un-agriculteur-dont-l-exploitation-etait-en-difficulte-963138.html&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://francais.rt.com/france/19526-hauts-seine&amp;#8212;&amp;#8203;tabassee-pour&quot; class=&quot;bare&quot;&gt;https://francais.rt.com/france/19526-hauts-seine&amp;#8212;&amp;#8203;tabassee-pour&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Et vous ?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle and Kotlin, a personal perspective</title>
      <link>https://melix.github.io/blog//2016/05/gradle-kotlin.html</link>
      <pubDate>Sun, 22 May 2016 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2016/05/gradle-kotlin.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gradle_embraces_kotlin_what_about_groovy&quot;&gt;Gradle embraces Kotlin, what about Groovy?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, it&amp;#8217;s been a long time since I last blogged, and I&amp;#8217;d like to remind that everything written here are opinions of my own and not the views of my employer, which happens to be Gradle Inc as write those lines.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A few days ago, &lt;a href=&quot;https://gradle.org/blog/kotlin-meets-gradle/&quot;&gt;Gradle and Jetbrains announced a partnership to make Kotlin a first class language for Gradle builds&lt;/a&gt;, both for build scripts and plugins. Most likely, you know Gradle has been using Groovy since its inception. Lots of people think that Gradle is written in Groovy, which is actually wrong. Most of Gradle is written in Java. The builds scripts are written in Groovy, lots of plugins are written in Groovy, our test cases are written in Groovy (using the best testing framework out there, Spock), but Gradle itself is written in Java.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;From my perspective, this is situation has been very disturbing and continues to be so. I have very good friends in the Groovy community, and this move has been seen by some of them as a betrayal. As an Apache Groovy committer, and someone who spent almost 4 years full time implementing new features of the language, most importantly its static compiler, seeing Kotlin promoted as the language of choice for Gradle&amp;#8217;s future, it&amp;#8217;s a little &lt;em&gt;strange&lt;/em&gt;. One could legitimely say, &lt;em&gt;WTF?&lt;/em&gt; I&amp;#8217;ve been aware of this work for several months now, and my colleagues Rodrigo B. de Oliveira and Chris Beams have done an amazing job in a very short period of time. From a long time Groovy user and Groovy developer point of view, it&amp;#8217;s hard not to make this move an emotional thing. However, business is not about emotions. In particular, what are we trying to acheive with Gradle? We&amp;#8217;re trying to help developers build their applications. We&amp;#8217;re trying to make this elegant, reproducible, scalable and fast. We&amp;#8217;re language agnostic. We can build Java, Groovy, Scala, Kotlin, C++, Python, &amp;#8230;&amp;#8203; Gradle has never been the tool to build Groovy applications: it&amp;#8217;s been a tool to build software. It&amp;#8217;s a tool about automation. And I&amp;#8217;ve been complaining enough about communities that build their own tool for their very specific language to understand that this is super important: Gradle is (or aims at) the best tool for building any kind of software. In short, we must think in terms of what is best for our users, and sometimes, this means changing technogies. A product should not be bound to a technology, but a company should even less be bound to it. And given the response that we had after the announcement, supporting Kotlin seem to drive a lot of excitement around Gradle, and that&amp;#8217;s a very good thing. So, let&amp;#8217;s take that out, and think what it means for Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovy_support_is_not_abandoned&quot;&gt;Groovy support is not abandoned&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, I already said it several times, but better continue to spread the message: support for Groovy in Gradle is &lt;strong&gt;not&lt;/strong&gt; deprecated nor removed. You can still write your scripts in Groovy, you can write your plugins in Groovy, and you will still be able to do it. But Gradle will likely encourage users to migrate to Kotlin. To be clear, Kotlin support is incubating, and there&amp;#8217;s a lot to do to make it as usable as the Groovy version. Second, there are tens of thousands of builds written using Groovy, hundreds of plugins written in Groovy, so it&amp;#8217;s not tomorrow that Kotlin is going to replace Groovy. However, we care about the future, so we need to think about what it means in the long term. Should we be excited about supporting Kotlin? Yes we should, because Kotlin is an amazing language. Should we continue to be excited about Groovy? Of course we should, because it&amp;#8217;s also an amazing language. But it&amp;#8217;s old and as such brings a lot of legacy with it. As someone who implemented the static compiler for Groovy, I know it very well. There are things that are hard to change, because a large part of the Groovy community is very fond of its dynamic behavior.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So let&amp;#8217;s focus on the two major aspects that led to embracing Kotlin in Gradle. The fist one, and principal, is IDE support. Let&amp;#8217;s face it: even before I joined Gradle, when I was giving talks about it, people were complaining about IDE support. Compared to a tool like Maven, supporting Gradle build scripts is complicated. Supporting XML is easy (to some extent). Supporting a &lt;em&gt;dynamic DSL&lt;/em&gt; is not. Some say it&amp;#8217;s Groovy&amp;#8217;s fault, and I want to correct this statement right now: it&amp;#8217;s not Groovy&amp;#8217;s fault. While Groovy let&amp;#8217;s you design dynamic DSLs, the design of the DSL can be changed to make it easier for tools to &quot;discover&quot; things. But when Gradle was designed, there wasn&amp;#8217;t any statically compiled Groovy. The idiomatic way to write DSLs in Groovy, at that time, was to heavily rely on &lt;em&gt;runtime metaprogramming&lt;/em&gt;. While loving &lt;em&gt;metaprogramming&lt;/em&gt;, I&amp;#8217;ve always prefered &lt;em&gt;compile time&lt;/em&gt; metaprogramming over &lt;em&gt;runtime&lt;/em&gt; metaprogramming. For multiple reasons:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;because in most cases, what you want to do at runtime can be done in a unique, setup phase. For example, create your metaclasses, enrich existing types, configure &lt;em&gt;property missing&lt;/em&gt;, &lt;em&gt;method missing&lt;/em&gt;, &amp;#8230;&amp;#8203; If it&amp;#8217;s setup, it&amp;#8217;s better done at compile time, because you can report errors, and because it gives higher performance. This led the way I designed the static compiler, and more features of Groovy after that (traits, type checking extensions, &amp;#8230;&amp;#8203;) : describe what you want to do at compile time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;because it makes the life of tools easier. While IntelliJ or Eclipse support &lt;em&gt;DSL descriptors&lt;/em&gt; that help them provide completion, those are hard to implement, and often inaccurate. They can only approximate what is going to happen at runtime. And in the end, you&amp;#8217;re doing the same job twice: you&amp;#8217;re writing a runtime for your DSL, which is dynamic, then you need to write a DSL descriptor for the IDE to understand it. Wouldn&amp;#8217;t it be better if all was done in a unique place? Something that both the compiler and the IDE can understand?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So while we &lt;em&gt;know&lt;/em&gt; we can describe dynamic Groovy DSLs so that they are understood by IDEs, it&amp;#8217;s effectively a lot of work. And if you want to support multiple IDEs, it&amp;#8217;s even more work. But in the case of Gradle, it&amp;#8217;s even worse: each plugin can provide it&amp;#8217;s own &quot;micro DSL&quot;. While there&amp;#8217;s an &quot;idiomatic&quot; way to configure Gradle builds, it&amp;#8217;s no single rule. One can implement it&amp;#8217;s own Groovy DSL within the Gradle build. And no luck the IDE would ever understand it. Another pain point is that Gradle adds complexity to complexity in terms of DSL capabilities. For example, when you have a build script that has:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;dependencies {
   compile libraries.groovy
}

greeter {
   message = &apos;hello&apos;
}

sign {
   signature = top
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;often people do not realize that:
   - &lt;code&gt;dependencies&lt;/code&gt; is found on a &lt;code&gt;Project&lt;/code&gt; instance
   - &lt;code&gt;libraries&lt;/code&gt; is a user declared variable, that can be found in a plugin, another build script, a project properties file, &amp;#8230;&amp;#8203; (how does the IDE find about it?)
   - &lt;code&gt;greeter&lt;/code&gt; is a &lt;em&gt;convention object&lt;/em&gt;, defined by a plugin, to configure the default values of its task
   - &lt;code&gt;sign&lt;/code&gt; is a &lt;em&gt;task&lt;/em&gt;, which has a &lt;code&gt;signature&lt;/code&gt; property, and &lt;code&gt;top&lt;/code&gt; references an &lt;em&gt;extension property&lt;/em&gt; from the project&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So while this build script is &lt;em&gt;simple to read&lt;/em&gt;, it&amp;#8217;s &lt;em&gt;hard to understand how it effectively works&lt;/em&gt;, because objects can be found at different places, can be provided by different providers (plugins, properties, extensions), but everything is accessed using a single notation. This is bad, because it makes it almost impossible for an IDE to understand what is going on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The question is, is it Groovy&amp;#8217;s fault? My answer is &lt;em&gt;not totally&lt;/em&gt;. The fault is mostly on the DSL design, and Groovy made it too easy to do so. But again, that was designed at a time when dynamic Groovy was the rule. I gave a talk, recently, about &lt;a href=&quot;https://www.google.fr/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwiW2Mftt-7MAhWKSRoKHQJtCcIQtwIIHTAA&amp;amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DnqqGtdvPzus&amp;amp;usg=AFQjCNH57qeR_jUUIAmGKZiQOK99v0669w&quot;&gt;building modern DSLs with Groovy&lt;/a&gt;, where I discourage such practices, and encourage the use of &lt;em&gt;static DSLs&lt;/em&gt; instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That leads me to the second main reason of embracing Kotlin in Gradle: performance. When we talk about performance, lots of folks tend to think that Groovy is slow. This is not the case. Groovy is pretty fast. However, depending on the design of the DSL, you can easily fall into traps that can lead to catastrophic performance. Before I go further with it, I&amp;#8217;m reading way to often that Gradle is slow &lt;em&gt;because it&amp;#8217;s written in Groovy&lt;/em&gt; and that &lt;em&gt;Groovy is dynamic so it&amp;#8217;s slow&lt;/em&gt;. F* no, those who tell you that just didn&amp;#8217;t profile a build. As I said, Gradle is mostly written in Java. And I&amp;#8217;ve spent the last 3 months optimizing the performance of Gradle, and I can tell you that of the dramatic performance improvements that one can see in Gradle 2.13 and 2.14, almost none was obtained by rewriting Groovy to Java, or rewriting Groovy code. None! Most of the hotspots were pure Java code. Period. However, as soon as you use plugins, which are today mostly written in dynamic Groovy, or that your build scripts imply a lot of nested closures, things start to become complicated for &quot;Groovy&quot;. Let me explain that clearly. I think at some point, someone made a terrible design decision in Groovy. I don&amp;#8217;t know who it was, but the idea was to rely on exceptions to control the flow of resolution of properties. This means that when a property is &lt;em&gt;missing&lt;/em&gt;, typically in a closure, an exception is thrown. When a method is not found, an exception is thrown. When a property is not found, an exception is thrown. That seemed to be a good idea, because in the end, you want to provide the user with an error, but in practice, this is catastrophic, because Groovy can capture those exceptions. Typically, in a delegation chain (nested closures), a containing closure or class can actually have this property defined, or implement &lt;em&gt;property missing&lt;/em&gt;/&lt;em&gt;method missing&lt;/em&gt;. Now, re-think a second about the &quot;simple&quot; example of Gradle build above: how do you now where to look up for &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;signature&lt;/code&gt;, &amp;#8230;&amp;#8203;? Now you know: f* exceptions are thrown, stack traces are filled, and eventually captured because some composite dynamic object finally wants to answer the message&amp;#8230;&amp;#8203; In practice, for some builds I have profiled, it was tens of thousands of exceptions being thrown and stack traces filled for nothing. And that has a terrible impact on performance. So even if we have implemented strategies in Gradle to try to avoid throwing those exceptions (which are responsible for part of the performance improvements in 2.14), this is very hard to do it, and we&amp;#8217;re still throwing way too many of them. A static language doesn&amp;#8217;t have this problem, because every single reference in source is resolved at compile time. So, if you&amp;#8217;re writing a plugin in Groovy, for the sake of performance, please add &lt;code&gt;@CompileStatic&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So there goes Kotlin. Kotlin has excellent static builders support, that make it practical both for IDE support, which will dramatically improve user experience in terms of understanding what do write, what is an error, having documentation, refactorings, &amp;#8230;&amp;#8203; and is a very pleasant language to work with. Honestly, I don&amp;#8217;t have anything bad to say about the language (apart from the &lt;em&gt;fun&lt;/em&gt; keyword that I don&amp;#8217;t like). To some degree, it&amp;#8217;s not very surprising: Kotlin has heavily inspired by Groovy and another popular JVM language: Scala. And again, being the one behind the static compiler of Groovy, I can&amp;#8217;t blame them for doing what I like about static languages. Their builder support is awesome, and very elegant. And it&amp;#8217;s supported out of the box by IntelliJ of course, but also Eclipse.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_static_dsl_for_groovy&quot;&gt;A static DSL for Groovy?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, so one might think at this point that I&amp;#8217;m mad. I wrote a &quot;competing&quot; language, and I&amp;#8217;m happy to see Kotlin being promoted in Gradle. I wrote the static compiler, that is capable of doing everything Kotlin can do (minus reified generics, plus superior scripting support, type checking extensions, &amp;#8230;&amp;#8203;), so wtf? Ok, so let&amp;#8217;s be very clear: I have absolutely no doubt that Groovy can do everything that we&amp;#8217;ve done with the Kotlin support in Gradle. It can be statically compiled, provide an elegant DSL that is statically compiled, and it can be understood by the IDE. I had no doubt before the Kotlin work started, I have even less doubts now. And I can say I have no doubts because I tried it: I implemented experimental support for statically compiled Gradle scripts, written in Groovy. Here&amp;#8217;s an example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;apply plugin: &apos;java&apos;
apply plugin: &apos;eclipse&apos;
apply plugin: &apos;idea&apos;
apply plugin: &apos;groovy&apos;
apply plugin: GreetingPlugin

repositories {
    mavenCentral()
}

dependencies {
    compile &apos;commons-lang:commons-lang:2.5&apos;
    compile &quot;commons-httpclient:commons-httpclient:3.0&quot;
    compile &quot;commons-codec:commons-codec:1.2&quot;
    compile &quot;org.slf4j:jcl-over-slf4j:1.7.10&quot;
    compile &quot;org.codehaus.groovy:groovy:2.4.4&quot;
    testCompile &apos;junit:junit:4.12&apos;
    runtime &apos;com.googlecode:reflectasm:1.01&apos;
}

tasks.configure(&apos;test&apos;, Test) {
    jvmArgs &apos;-XX:MaxPermSize=512m&apos;, &apos;-XX:+HeapDumpOnOutOfMemoryError&apos;
}

dependencies {
    compile &apos;org.codehaus:groovy:groovy-all:2.4.4&apos;
}

extension(GreetingPluginExtension) {
    message = &apos;Hi&apos;
    greeter = findProperty(&apos;greeter&apos;)?:&apos;static Gradle!&apos;
}

tasks.create(&apos;dependencyReport&apos;, DependencyReportTask) {
    outputs.upToDateWhen { false }
    outputFile = new File( project.buildDir, &quot;dependencies.txt&quot;)
}

class GreetingPlugin implements Plugin&amp;lt;Project&amp;gt; {
    void apply(Project project) {
        project.extensions.create(&quot;greeting&quot;, GreetingPluginExtension)
        project.task(&apos;hello&apos;) &amp;lt;&amp;lt; {
            println &quot;${project.extension(GreetingPluginExtension).message} from ${project.extension(GreetingPluginExtension).greeter}&quot;
        }
    }
}

class GreetingPluginExtension {
    String message
    String greeter
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is an example Gradle build that is compiled statically. It has none of the problems I described about the Groovy implementation in Gradle above. It uses all the techniques that static Groovy provides: extension methods, powerful scripting with implicit imports, type checking extensions, &amp;#8230;&amp;#8203; All this works. And interestingly, the work that is done to enable support for Kotlin also benefits to statically compiled Groovy, and Java! Let&amp;#8217;s not forget about the latter, which is years behind in terms of &quot;modern&quot; languages support. So if this works, why do we need Kotlin? To be honest, I asked it to myself many times. It was very difficult to me, because I knew Groovy could do it. Again, I had no doubt about the language capabilities, no doubt about the performance impact of doing this. However, I missed two critical points:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;IDE support. Even if support of Groovy in IntelliJ is by far the most advanced of all other IDEs, it still lacks behind when static compilation is on. But more importantly, it doesn&amp;#8217;t know that my script is statically compiled, nor does it now about my custom extension methods. I tried to implement a &lt;code&gt;GDSL&lt;/code&gt; descriptor to make it aware of them, and it somehow worked: I do have code completion, but errors are not marked as errors, and the IDE still doesn&amp;#8217;t understand that it should only suggest to me what is relevant in the context. With Kotlin scripts which are &lt;em&gt;natively static&lt;/em&gt;, there&amp;#8217;s no such issue. The IDE understands everything natively, in IntelliJ and Eclipse. So, I have no doubt that Jetbrains can implement support for this, just like I had no doubt I could implement a static Groovy DSL, but who is going to write this? Me? Gradle? I don&amp;#8217;t have the time to do it. And it&amp;#8217;s not Gradle&amp;#8217;s job to write IDE plugins. And what about Eclipse? One big issue that the Groovy community has, &lt;strong&gt;today&lt;/strong&gt;, is that nobody is supporting Eclipse since Pivotal dropped sponsorship of Groovy. After more than one year, nobody took over the development of Groovy Eclipse. Nobody. While Groovy itself saw lots of new contributors, while we saw a lot of bugfixes, new contributors and that the download numbers where never as high as they are today, IDE support is critical. And nobody took over the development of it. I saw some people referring to what Jetbrains is doing as &quot;blackmailing&quot;. Seriously? Jetbrains? Think of what they&amp;#8217;ve done for Groovy. Groovy would never has been as popular as it is without them. They provided us with the best Groovy IDE possible. They are constantly supporting new features of the language, adding support for AST transformations, traits, &amp;#8230;&amp;#8203; They even added the ability, in IDEA 14, to use Groovy (and not Kotlin, guys!) as the language to evaluate expressions in the debugger. And they would try to kill Groovy? Kill part of their business? Come on guys! So yes, they invested a lot in Kotlin and want to promote it, but how could it be otherwise? And it&amp;#8217;s not like if the language sucked: it&amp;#8217;s awesome!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Does it make sense? Now that we made the decision to support Kotlin, that we proved it would provide the level of user friendliness we want and that it is statically compiled by default, does it make sense to put resources to support static Groovy in addition? I don&amp;#8217;t have an answer to this. I thought yes, but now I&amp;#8217;m not sure. Kotlin does the job. And honestly, they have great engineers working on the language. Even if it lacks behind in terms of scripting and compilation times compared to Groovy, I have no doubt they will fix it. How arrogant would we be if we thought other languages could not do what we&amp;#8217;ve done with Groovy?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_future_of_groovy&quot;&gt;The future of Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last point I want to address is what it means for the future of Groovy, and what it means for &lt;strong&gt;my&lt;/strong&gt; future in Groovy. First of all, I always thought that the future of Groovy was in the hands of its community. It&amp;#8217;s not Gradle that has Groovy&amp;#8217;s future in its hands. It&amp;#8217;s &lt;strong&gt;you&lt;/strong&gt;. The move to the Apache Software Foundation was also done for this very same reason: community first. If you want to continue to use Groovy, to improve it, to support it, all you have to do is f* do it! And I will continue! I love this language, I know too well how far it can go in terms of DSL support, AST transformations, now in 2.5 we have macros, that&amp;#8217;s just a crazily powerful language that&amp;#8217;s super fun to use. Should we fear competition? No, we shouldn&amp;#8217;t. Competition is good. It should be inspiring. And if Gradle moving to Kotlin means the death of Groovy, maybe the problem is elsewhere. And even if lots of people get introduced to Groovy through Gradle, it&amp;#8217;s not the only entry point. Grails is another. Jenkins (through Flow) is another. And many, many more. There was a tweet a few days ago which showed the 100 most popular dependencies in GitHub projects. Groovy was one of them. No Kotlin. No Scala. Groovy. It&amp;#8217;s everywhere, and it&amp;#8217;s going to be there for a long time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Part of the fears of the community is, after the Pivotal demise, if Groovy is a dying language. It&amp;#8217;s not. It has never been so widely used. The move to Apache Software Foundation drove a lot of attention and brought us many more contributors. But the community has to realize what the problems with Groovy are, and it has to face them: the introduction of the static compiler was too late. IDE support is important. Java 9 support is going to be super important. If you love your language, contribute. Help it. Help yourselves. The future of Groovy &lt;strong&gt;must&lt;/strong&gt; be in your hands. I can&amp;#8217;t recall how many times I told this, since I joined VMware, a few years ago, to develop Groovy. In every talk I give, I&amp;#8217;m always telling how important it is that &lt;strong&gt;you&lt;/strong&gt; contribute. Jetbrains is not going to write Groovy Eclipse for you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And I would like to finish with one word: if people move from Groovy to Kotlin, is it really a problem? Isn&amp;#8217;t any technology inspired by another? Aren&amp;#8217;t we, developers, always rebuilding the same things, but improving them, learning lessons from the past? Is Kotlin a better Groovy? I don&amp;#8217;t have the answer yet. Maybe it is. Maybe not. Today Groovy remains greatly superior in terms of scripting, DSL support, but it comes with a price that Gradle doesn&amp;#8217;t want to pay. And let&amp;#8217;s not forget the original community of Groovy: a &lt;strong&gt;dynamic&lt;/strong&gt; language for the JVM. There are still &lt;strong&gt;lots&lt;/strong&gt; of people who like this aspect of the language (and I do too, typically when I write Groovy scripts in place of bash scripts, I don&amp;#8217;t care about types). It&amp;#8217;s compile time metaprogramming features also make it incredibly powerful. Modern Groovy definitely doesn&amp;#8217;t deserve its &quot;bad press&quot;. Would you compare Java 8 with Java 1? No. So don&amp;#8217;t compare Groovy 2.4 with Groovy 1 either. Reputation should change, and you can help there too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This leads me to what I should do. And there, I&amp;#8217;m a bit lost, to be honest. I work for a company that embraced Groovy, that is now embracing Kotlin. I love my job, I love working with Gradle, I love Groovy, and I quite enjoy Kotlin. I&amp;#8217;m a passionate developer. I just want to continue having fun. But if you think that as such, I&amp;#8217;m not a good representative of the Groovy community anymore, maybe I should step off from the Groovy project. I would hate that, but I&amp;#8217;ve kind of been hurt by the bad comments we (Gradle) received from some members of the Groovy community. I don&amp;#8217;t want to fall into a language war, I don&amp;#8217;t care about this. I care about users. What I love to do is helping people, period.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I would like to finish this post with a thought about what I&amp;#8217;m going to do, as a Gradle developer, for you, Groovy users. In particular, I am convinced that the success of Gradle is largely due to its Groovy DSL, despite its problems. The fact that it&amp;#8217;s simple, easy to read, is super important. I joined the Groovy project because I was using Groovy as a DSL platform in a natural language processing context. Groovy is super powerful for this. And I learnt a lot in terms of DSL design. In particular, I will try to make sure that it doesn&amp;#8217;t become a Kotlin API. What I mean by that is that I think we should elevate from a Groovy DSL to a Gradle language. And this language is meant at &lt;strong&gt;describing&lt;/strong&gt; builds. And our users are not Kotlin developers. Most of them are not Groovy developers either. They are, as I described earlier, from different horizons. And I would hate if a user would have to understand concepts like generics or type inference to write a build script. That would be horribly wrong. A build author should understand how to &lt;em&gt;model an application&lt;/em&gt;, not what is a type, what is an extension method, or generic return type inference. It&amp;#8217;s different for &lt;em&gt;plugin authors&lt;/em&gt;, but for a &lt;em&gt;build author&lt;/em&gt;, it&amp;#8217;s super important. So I will try to make sure that Kotlin scripting support improves, even if it means that it would go even closer to what Groovy supports. I would do this not because I want Groovy to die, I don&amp;#8217;t (and it wouldn&amp;#8217;t help my royalties for Groovy in Action 2 ;)), but it would help users or Gradle. That&amp;#8217;s what I care most about, just like I care about what Groovy users want when I work on the Groovy project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As for talking about Gradle, Groovy and its future, I&amp;#8217;ll be a GR8Conf next week, I&amp;#8217;d be happy to answer you in person there too!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Keep on Groovying!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A week fighting a PermGen leak</title>
      <link>https://melix.github.io/blog//2015/08/permgenleak.html</link>
      <pubDate>Sat, 29 Aug 2015 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2015/08/permgenleak.html</guid>
      	<description>
	&lt;h1 id=&quot;_a_challenge_at_gradle&quot; class=&quot;sect0&quot;&gt;A challenge at Gradle&lt;/h1&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_new_job&quot;&gt;A new job&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is my first blog post after 4 months being a full time employee of &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle Inc.&lt;/a&gt;! I am pretty excited by this job, even though so far it didn&amp;#8217;t give me much time to contribute to &lt;a href=&quot;https://groovy-lang.org&quot;&gt;Apache Groovy&lt;/a&gt; (but we did manage to release 2.4.4 though). One of the reasons I joined the company was because I love technical challenges. And &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; has a lot of them, with an incredible team of smart people working together to make software automation better. This week, I worked on my first true challenge, and I must confess that I miserably failed :-) This is a long post, and anyone who ever fought against the infamous &quot;PermGen space error&quot; in their application is going to understand why&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_codenarc_as_the_source_of_a_leak&quot;&gt;CodeNarc as the source of a leak?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first suspicious piece of code that draw our attention was &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt;. CodeNarc is a source code quality analysis tool for Groovy, which is used by a lot of Groovy developers, including in Gradle itself (since Gradle intensively makes use of Groovy). &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; can be seen as the equivalent of FindBugs for Groovy code. And problems seemed to start with an upgrade of the Gradle CodeNarc plugin to use CodeNarc 0.23. We actually saw reports like &lt;a href=&quot;https://discuss.gradle.org/t/codenarc-performance-drop-after-versions-update/9677&quot;&gt;this one&lt;/a&gt; in the forums or &lt;a href=&quot;https://github.com/CodeNarc/CodeNarc/issues/116&quot;&gt;this other one&lt;/a&gt; in GitHub but thought that the PermGen error was just a consequence of &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; including more rules: rules are written in Groovy, so compiled down to classes and classes eat PermGen. So increasing the PermGen space was enough, and it did actually solve the error. Problem solved. Or not. The riddle only started for me with a seemingly insignificant question on our internal mailing lists: &quot;Can some investigate why our build sometimes fails with a PermGen space error?&quot;, and I volunteered.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Interestingly, I had just finished pushing an upgrade of &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; to Groovy 2.4.4 on our master branch, and I had noticed that I had to increase the PermGen space too. At first, I naively thought that it was also required because Groovy 2.4 consumed more memory, but I was wrong. I should have known, because before joining Gradle, I had actually worked on Groovy for Android, and a consequence of this work was that Groovy 2.4 had a reduced memory footprint: we generate less bytecode, which directly relates to a reduced PermGen space usage. So why on earth would Groovy 2.4 require more memory? And what is the relation with the CodeNarc plugin? Actually this plugin works in a Gradle version that uses Groovy 2.3.10, so why would there be a relation between the two?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In such a case, your best friend is a profiler. But as I will explain here, it can also lead you to wrong tracks. Be careful. The second best friend is the JVM options &lt;code&gt;-XX:+TraceClassLoading&lt;/code&gt; and &lt;code&gt;+XX:+TraceClassUnloading&lt;/code&gt;. I also used &lt;code&gt;-XX:SoftRefLRUPolicyMSPerMB=0&lt;/code&gt;, an option that I had no idea it existed before my friend David Gageot told me. Basically, it will force the garbage collector to agressively collect all soft references, which is very useful to understand, in combination with the 2 other options, from which classloader we are leaking memory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first wrong track was actually thinking that &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; was the source of the problem. I &lt;a href=&quot;https://groups.google.com/d/topic/gradle-dev/w9F0PsCfI4Y/discussion&quot;&gt;wrote an email on the gradle-dev list&lt;/a&gt;, explaining my findings, and I had indeed found a lot of classes from &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; were not unloaded. Before I go further, let&amp;#8217;s explain how the JVM is supposed to behave with regards to classes in Java 7. We all know that objects are garbage collected, but for a lot of people, classes are not. That&amp;#8217;s why we have the PermGen space (which has disappeared in Java 8 but that&amp;#8217;s another story): this segregated space of the JVM memory is used to store classes. And in Java, a class is loaded by a classloader. There is a strong reference between a class and its classloader. But what the JVM is able to do is actually simple: if there&amp;#8217;s no instance of the class which is strongly reachable &lt;strong&gt;and&lt;/strong&gt; that the classloader is neither strongly reachable, then both the class and the classloader can be unloaded. This means that PermGen can be recovered, and it is pretty useful, especially for a language like Groovy which can generate a lot of classes at runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Gradle, and particularily in the Gradle CodeNarc plugin, &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; is executed through an Ant task, which spawns its own isolated classloader, containing both the &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; and Groovy classes. So when the plugin execution is finished, if we do not keep track of the classloader, classes should be garbage collected. So a good candidate for the memory leak was actually the &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; that Gradle uses to execute the Ant task. And guess what? There is such a leak, because the &lt;code&gt;DefaultIsolatedAntBuilder&lt;/code&gt; performs classloader caching! That was also discovered by my colleague Sterling, who immediately spot that: while we do cache the classloaders, keeping a strong reference on them, we don&amp;#8217;t have any code to release the classloader in case of memory pressure. Conclusion, we&amp;#8217;ve found the memory leak, hurray! And it has nothing to do with &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; or &lt;a href=&quot;https://groovy-lang.org&quot;&gt;Apache Groovy&lt;/a&gt;, pfiew!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I immediately tried to disable the cache, which turned to be pretty trivial. Run the build again and&amp;#8230;&amp;#8203; another PermGen space error. No CodeNarc classes unloaded, no Groovy classes unloaded. Wow. So the problem wasn&amp;#8217;t solved, first &quot;oh my!&quot; moment of the week: there was &lt;strong&gt;another&lt;/strong&gt; leak.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One test I did, then, is to totally comment out the code that, in the ant builder code, performed the definition of the CodeNarc task. Eventually, there was only that code left in the CodeNarc plugin:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;    @TaskAction
    void run() {
        logging.captureStandardOutput(LogLevel.INFO)
        def classpath = new DefaultClassPath(getCodenarcClasspath())
        antBuilder.withClasspath(classpath.asFiles).execute {
            // ... thou shalt not leak!
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I executed the code again, and there was definitely a leak: after several loops, a PermGen error occurred. &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; was ruled out as the source of the leak. After some hours of trials, study of memory snapshots, I eventually came out with a piece of code that reproduces the problem independently of Gradle:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;int i = 0;
try {
    while (true) {
        i++;
	URLClassLoader loader = new URLClassLoader(
            new URL[]{new File(GROOVY_JAR).toURI().toURL()},
            ClassLoader.getSystemClassLoader().getParent());
        Class system = loader.loadClass(&quot;groovy.lang.GroovySystem&quot;);
        system.getDeclaredMethod(&quot;getMetaClassRegistry&quot;).invoke(null);
        loader.close();
    }
} catch (OutOfMemoryError e) {
    System.err.println(&quot;Failed after &quot; + i + &quot; loadings&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, the code is very simple: it creates a new isolated classloader, which only contains Groovy on classpath. Then it invokes the creation of the Groovy runtime, by asking the metaclass registry, then it closes the classloader. On my JVM, after about 40 runs, the code fails with a PermGen space error: despite the fact that no class, no object is kept out of the classloader, the Groovy runtime is not unloaded, leading to a memory leak. The key point here is that I had noticed some oddities during my hours of debugging: a class, named &lt;code&gt;ClassInfo&lt;/code&gt;, was at the center of those oddities.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;https://groups.google.com/group/gradle-dev/attach/cb238029e9b0/leak.png?part=0.1&amp;authuser=0&quot; alt=&quot;ClassInfo leak&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, although &lt;a href=&quot;https://www.yourkit.com/features/&quot;&gt;YourKit&lt;/a&gt; (the profiler I was using) was telling me that all classes, all classloaders were weakly or softly reachable (btw, it&amp;#8217;s really a pity that &lt;a href=&quot;https://www.yourkit.com/features/&quot;&gt;YourKit&lt;/a&gt; doesn&amp;#8217;t show them separately, that is, weakly referenced objects from softly referenced ones), the classes were not garbage collected. Also strangely, some classes appeared as GC roots, meaning they could be collected, but they weren&amp;#8217;t! And when I navigated through some of the duplicate classes I was seeing, &lt;code&gt;ClassInfo&lt;/code&gt; was present, as a value of a map entry of class value. Here we are, I had found the real source of the leak. Something had changed in Groovy. And the fact that &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; was leaking since 0.23 was just a side effect of upgrading its dependency to Groovy 2.4! So despite Gradle was using Groovy 2.3.10, CodeNarc, by default, was using a more recent version of Groovy. That doesn&amp;#8217;t explain &lt;strong&gt;why&lt;/strong&gt; it leaks yet, but we now know who is responsible: Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_classvalue_friend_or_foe&quot;&gt;ClassValue, friend or foe?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since Groovy 2.4, Groovy uses a new mechanism for storing its runtime metadata in case you run on JDK 7 or later: &lt;code&gt;ClassValue&lt;/code&gt;. &lt;code&gt;ClassValue&lt;/code&gt; allows storing information on the class level. Typically, a language like Groovy would use it to store the metaclass of a class. In practice, Groovy doesn&amp;#8217;t directly store the metaclass here, but a higher level concept called &lt;code&gt;ClassInfo&lt;/code&gt;, which in turns gives access to the metaclass of a class.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before Groovy 2.4, all that information was stored directly in the &lt;code&gt;ClassInfo&lt;/code&gt; class itself, through a private static field. &lt;code&gt;ClassInfo&lt;/code&gt; is therefore the global entry point for accessing runtime information about a class. While Groovy 2.4 still uses &lt;code&gt;ClassInfo&lt;/code&gt; as an entry point, there are 2 possible storage mechanisms, based on the underlying JDK. If &lt;code&gt;ClassValue&lt;/code&gt; is available; which is the case for any JDK 7+, then it is used, otherwise we fallback on the old mechanism. &lt;code&gt;ClassValue&lt;/code&gt; is supposed to be more efficient and more direct. Of course, in any case (old and new storage mechanism), it is memory sensitive: in case a class is not available anymore, its &lt;code&gt;ClassInfo&lt;/code&gt; is removed. What &lt;code&gt;ClassValue&lt;/code&gt; storage provides is basically the same as ThreadLocal, but at the Class level instead of the Thread level. Users are allowed to store information here, but one should be aware that as thread locals, if you start using it, you may face memory leaks if you don&amp;#8217;t use it properly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s for the theory, let&amp;#8217;s see how in practice this change led to a giant memory leak in the Gradle build.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The theory is that &lt;code&gt;ClassValue&lt;/code&gt; should behave like ThreadLocal. That is, the entries stored in the internal map of the Class class, should be garbage collected when the referent is not strongly referenced anymore. This behavior is however not what the JVM does. It was confirmed to me by Charles Nutter (JRuby) a few hours later: although we all expected the JVM to collect the unreachable, it does not.&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;fr&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://twitter.com/iNikem&quot;&gt;@inikem&lt;/a&gt; &lt;a href=&quot;https://twitter.com/CedricChampeau&quot;&gt;@cedricchampeau&lt;/a&gt; I talked with &lt;a href=&quot;https://twitter.com/haupz&quot;&gt;@haupz&lt;/a&gt; at JVMLS and he agrees that ClassValue *should* work like ThreadLocal wrt dereferencing.&lt;/p&gt;&amp;mdash; Charles Nutter (@headius) &lt;a href=&quot;https://twitter.com/headius/status/636910965817143297&quot;&gt;27 Août 2015&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Uh. Second &quot;oh my!&quot; moment of the week. I had now a candidate (Groovy) and a reason (&lt;code&gt;ClassInfo&lt;/code&gt; leaking). However, it doesn&amp;#8217;t explain by itself why the class loader is not garbage collected: if Groovy stores information on classes, it&amp;#8217;s ok, as long as the classes to which it writes some metadata are from the classloader, or any child classloader, of the Groovy runtime itself. Everything would be self-contained, meaning we would have a graph of objects that do not leak outside of the isolated classloader. However&amp;#8230;&amp;#8203; Groovy uses Strings, integers, List, &amp;#8230;&amp;#8203; all coming from the system classloader. And that is the main difference with the old metadata storage mechanism: the old one only &lt;strong&gt;referenced&lt;/strong&gt; classes from the system classloader. With &lt;code&gt;ClassValue&lt;/code&gt;, we are &lt;strong&gt;modifying&lt;/strong&gt; classes from the system classloader too! That is, the String class, for example, contains in its class value map, information from the Groovy runtime! The famous &lt;code&gt;ClassInfo&lt;/code&gt; instance is present there! There we are! We leaked a &lt;code&gt;ClassInfo&lt;/code&gt; instance into the system classloader! So what happens is that when we are done with our &quot;isolated&quot; Groovy runtime, we think it should unload because nothing references any object or class from that classloader. However, the Groovy runtime did update classes from the system classloader, and it started leaking into it! The ghost in the shell! Groovy is spoiling everywhere&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So far so good, I had the explanation, I could write a workaround: let&amp;#8217;s iterate over all those classes that Groovy updated, remove the &lt;code&gt;ClassInfo&lt;/code&gt;, and we&amp;#8217;re done. I wrote that code, and it turned out to be a bit ugly, but&amp;#8230;&amp;#8203; it worked! Here is, for information, the cleanup code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;    static void removeClassFromGlobalClassSet(Class&amp;lt;?&amp;gt; classInfoClass) throws Exception {
        Field globalClassValueField = classInfoClass.getDeclaredField(&quot;globalClassValue&quot;);
        globalClassValueField.setAccessible(true);
        Object globalClassValue = globalClassValueField.get(null);
        Method removeFromGlobalClassValue = globalClassValueField.getType().getDeclaredMethod(&quot;remove&quot;, Class.class);
        removeFromGlobalClassValue.setAccessible(true);

        Field globalClassSetField = classInfoClass.getDeclaredField(&quot;globalClassSet&quot;);
        globalClassSetField.setAccessible(true);
        Object globalClassSet = globalClassSetField.get(null);
        globalClassSetField = globalClassSet.getClass().getDeclaredField(&quot;items&quot;);
        globalClassSetField.setAccessible(true);
        Object globalClassSetItems = globalClassSetField.get(globalClassSet);

        Field clazzField = classInfoClass.getDeclaredField(&quot;klazz&quot;);
        clazzField.setAccessible(true);


        Iterator it = (Iterator) globalClassSetItems.getClass().getDeclaredMethod(&quot;iterator&quot;).invoke(globalClassSetItems);

        while (it.hasNext()) {
            Object classInfo = it.next();
            Object clazz = clazzField.get(`ClassInfo`);
            removeFromGlobalClassValue.invoke(globalClassValue, clazz);
        }

    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After executing that code, no &lt;code&gt;ClassInfo&lt;/code&gt; instance was leaking anymore into the system classloader, and the runtime could be shutdown properly. The garbage collector did its job, and yay! I&amp;#8217;m so happy, I&amp;#8217;ll be able to sleep soon! That was tuesday night. And that night, I thought I had found the solution.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_memory_sensitive_classloader_caching&quot;&gt;Memory sensitive classloader caching&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So wednesday, I spent the day trying to implement the same strategy inside Gradle. More precisely, inside the &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; thing I told you. I implemented the code, launched my test again and hurray! it worked! My test passed! No more PermGen space error! So all I had to do, now, was to reactivate classloader caching, otherwise, we would loose a feature that is important performance wise.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I reactivated the cache, and boom! That time, the Gradle build did &lt;strong&gt;not&lt;/strong&gt; fail with a PermGen error, but with very strange errors like this one:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.plus() is applicable for argument types: (java.lang.Integer) values: [0]
&amp;gt;  Possible solutions: plus(java.lang.String), plus(java.lang.Character), abs(), use([Ljava.lang.Object;), split(groovy.lang.Closure), minus(java.lang.Character)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mmmmmm&amp;#8230;&amp;#8203; 3rd &quot;oh my!&quot; moment of the week. I understood what I had just done. By clearing the &lt;code&gt;ClassInfo&lt;/code&gt; stuff from the classloader, I had effectively shutdown the Groovy runtime that was initiated in that cached classloader. So when some code was trying to reuse the runtime from that cached classloader, since I had disabled it, it was failing! And there&amp;#8217;s no option to reinitialize the Groovy runtime. It&amp;#8217;s just not doable, because everything happens in static initializers (private final fields, &amp;#8230;&amp;#8203;). So unless the JVM had an option to allow to re-execute the static initializers of a class (and who knows what oddities it would lead to), I had no luck.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s about when I told my mates at Gradle &quot;I think we have to choose between caching and leaking memory&quot;. But the night came, and I actually had an idea. I could implement a memory sensitive cache: by writing a smart cache structure with appropriate SoftReferences and reference queues, I would be able to execute the shutdown code only when I know that the GC is trying to reclaim memory. The idea is simple: we have a map, which key is a SoftRefence&amp;lt;String&amp;gt;, and the value is our cached classloader. The &lt;code&gt;String&lt;/code&gt; represents the classpath that we are caching for the classloader.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now imagine that the GC is out of memory. The semantics of &lt;code&gt;SoftReference&lt;/code&gt; are clear: before throwing an OutOfMemoryError, the JVM will do its best and clear all soft references. Doing so, using a custom reference queue, we can be notified that the reference is cleared. Then, we can execute the Groovy runtime shutdown code, which will in turn make the ClassLoader collectible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Honestly I was pretty happy with my implementation. I executed the code and it worked! Caching was working until the GC tried to reclaim memory, then I saw my shutdow code executed, memory reclaimed and green tests. Woooo!!! I had eventually knocked that memory leak down! Ha ha!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then I remembered that my colleague Sterling had a test which involved a loop in an integration test. To make sure I had &lt;strong&gt;really&lt;/strong&gt; fixed the leak, I asked him to tell me how he did that. The code was very simple, just involving a loop thanks to &lt;code&gt;@Unroll&lt;/code&gt; in a &lt;a href=&quot;https://docs.spockframework.org&quot;&gt;Spock specification&lt;/a&gt;. I did it and&amp;#8230;&amp;#8203; PermGen error showed up again. WAT?!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That was the fourth &quot;oh my!&quot; moment. And not the last one. I really then spent hours in modifying my caching code, refactored my code to add more complicated memory leak strategies, seeing that there were still thread locals, clearing them explicitly, adding a memory leak strategy for Ant itself, for the Java Beans introspector, &amp;#8230;&amp;#8203; None of my attempts worked. In the end, it always failed. But there was always one mystery: I saw that the Groovy classes were unloading. But the Ant classes were not&amp;#8230;&amp;#8203; And the rest, I should have discovered that much sooner. But when you have so many potential source leaks, that are much more evident, it&amp;#8217;s so hard to figure out.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In particular, one thing would have made things much easier to discover. In &lt;a href=&quot;https://www.yourkit.com/features/&quot;&gt;YourKit&lt;/a&gt;, you can see that there are duplicate classes. Classes that have the same name, but come from different class loaders. However, there&amp;#8217;s nothing that will &lt;strong&gt;show&lt;/strong&gt; you those duplicates. You have to find them yourself. And in the end, when in the dump you see an instance of that class, all you can see is that it is an instance of &lt;code&gt;ClassInfo&lt;/code&gt;. Nothing, visually, tells you that the instance of &lt;code&gt;ClassInfo&lt;/code&gt; that you are seeing actually comes from a different classloader from the one you are seeing just next to it. A bit of color, for example, would help&amp;#8230;&amp;#8203;. And it would have helped me seeing that some &lt;code&gt;ClassInfo&lt;/code&gt; elements that I was seeing in the classes from Ant didn&amp;#8217;t come from the &quot;disposable&quot; Groovy runtime&amp;#8230;&amp;#8203; No. They were coming from&amp;#8230;&amp;#8203; the Gradle runtime itself!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_where_it_all_ends&quot;&gt;Where it all ends&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, That was the last &quot;oh my!&quot; moment of the week. The one that killed all my hopes. And to understand the problem, I now have to explain to you how &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; works. It&amp;#8217;s a very small, yet very smart and practical piece of code. Maybe too smart.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle, as a core feature, lets you execute Ant tasks thanks to code inherited from the Groovy codebase itself: AntBuilder. It&amp;#8217;s a very elegant piece of code, that lets you write things like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;task check &amp;lt;&amp;lt; {
    ant.taskdef(name: &apos;pmd&apos;,
                classname: &apos;net.sourceforge.pmd.ant.PMDTask&apos;,
                classpath: configurations.pmd.asPath)
    ant.pmd(shortFilenames: &apos;true&apos;,
            failonruleviolation: &apos;true&apos;,
            rulesetfiles: file(&apos;pmd-rules.xml&apos;).toURI().toString()) {
        formatter(type: &apos;text&apos;, toConsole: &apos;true&apos;)
        fileset(dir: &apos;src&apos;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While this works, there&amp;#8217;s actually a lot involved behind that. Including classloader magic. In particular, in the example above, we create a task definition in Ant, which uses a classpath defined in Gradle. &quot;ant&quot; here is a global object which is shared accross the build, but it is possible to avoid the classes from the Ant tasks to be mixed with the Gradle classpath itself by using antBuilder instead. That&amp;#8217;s what the &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; plugin does:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;antBuilder.withClasspath(classpath.asFiles).execute {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;means &quot;Gradle, please, create an isolated classloader for me, that will contain the classpath only necessary for CodeNarc, and execute that Ant task with it&quot;. It seems very trivial, but there is a problem. The code that you see here is found in a Gradle script. It means that the &quot;antBuilder&quot; object that you are seeing here comes from Gradle. It is our &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; instance. When we call &quot;withClasspath&quot;, a new instance of &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; will be created, with an isolated classloader corresponding to the supplied classpath. Then calling execute with a closure that lets you configure the ant task using the Groovy AntBuilder syntax.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So the &quot;Closure&quot; class that we are seeing here comes from Gradle. Then, we have a classloader which contains the Ant runtime, and a &quot;bridge&quot; class, written in Groovy, called &quot;AntBuilderDelegate&quot;, which has one responsibility: when the code of the Ant builder is going to be executed, it is likely that the version of Groovy which will be found on classpath will be &lt;strong&gt;different&lt;/strong&gt; from the one that Gradle uses. That is exactly what happens with &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt;: Gradle 2.6 uses Groovy 2.3.10, but the &lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; plugin executes with Groovy 2.4.1, so the Ant task works with a different &quot;Closure&quot; class than the one that Gradle has. We will really have two distinct &quot;Closure&quot; classes here, and &quot;AntBuilderDelegate&quot; is responsible for filling the gap: when the Ant configuration code, which will use AntBuilder from the Ant classpath, is going to be executed, it will be calling AntBuilderDelegate instead of directly the Closure code. And that code will intercept the missing methods in order to &quot;reroute&quot; them to the builder. You don&amp;#8217;t have to understand that in detail, it&amp;#8217;s not really the point here, but it is important to understand that this &quot;AntBuilderDelegate&quot; class is instantiated&amp;#8230;&amp;#8203; in Gradle, using the Gradle classloader.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you may see it coming. I told you I had upgraded Gradle to use Groovy 2.4.4. So what does it mean? Gradle now uses Groovy with &lt;code&gt;ClassValue&lt;/code&gt;. And what is the problem with &lt;code&gt;ClassValue&lt;/code&gt;? All classes &quot;touched&quot; by Groovy will have them &quot;polluted&quot; with necessary metadata information. So when we create an instance of &quot;AntBuilderDelegate&quot;, we&amp;#8217;re doing that using the Groovy 2.4 runtime from Gradle, which comes with its own &lt;code&gt;ClassInfo&lt;/code&gt;. And that delegate references and AntBuilder which is instantiated using the Ant classloader, with a different Groovy runtime, having its own &lt;code&gt;ClassInfo&lt;/code&gt;. So what I had found earlier was that the &lt;code&gt;ClassInfo&lt;/code&gt; from the Groovy &quot;Ant&quot; runtime was leaking into Gradle. But I hadn&amp;#8217;t realized that the opposite was also true! By bridging the runtimes, we were leaking Groovy &quot;Gradle&quot; into the isolated classloader, through &lt;code&gt;ClassValue&lt;/code&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, what happened, is that the Groovy classes from the isolated classpath were garbage collected, because no &lt;code&gt;ClassInfo&lt;/code&gt; from Gradle leaked into them. However, the Ant classes were touched. And they were NOT collectible then.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And this is were I stopped. Because if I found a way to &quot;unload&quot; &lt;code&gt;ClassInfo&lt;/code&gt; from the isolated classpath and the touched classes from the system classloader, I haven&amp;#8217;t found a way to do the same for the &lt;code&gt;ClassInfo&lt;/code&gt; instances that leak into the Ant runtime&amp;#8230;&amp;#8203; Of course I tried a &quot;brute force&quot; thing, by removing all &lt;code&gt;ClassInfo&lt;/code&gt; from those classes, but as you understood, it&amp;#8217;s a desperate attempt: it&amp;#8217;s equivalent to shutting down the runtime. And then, it totally breaks subsequent calls in the Gradle build, we&amp;#8217;ve just broken the Groovy runtime from Gradle&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To add some confusion to the problem, I think it&amp;#8217;s now a good time to explain that I actually simplified the isolated ant builder classloader hierarchy. There are actually (at least) 3 classloaders involved:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The classloader from Gradle, which loads the Gradle runtime, the &lt;code&gt;IsolatedAntBuilder&lt;/code&gt; instance and also the &lt;code&gt;AntBuilderDelegate&lt;/code&gt; instance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A classloader for the Ant runtime, which is isolated from Gradle, apart from logging classes necessary for Gradle to be able to capture the output. This classloader is per classpath, and is the one which is cached.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A classloader that is &lt;strong&gt;filtering&lt;/strong&gt; some classes from the Gradle runtime classloader to make them available. This is what the bridging Ant builder uses. This classloader is shared among all isolated ant builder instances.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So when I say that something leaks, it can leak to any of those classloaders, and any of the parent loaders&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s were I felt desperate. After a week fighting those memory leaks, and so many &quot;ah ah, got you!&quot; moments, I was in front of a wall. Basically, while in the first case (isolated &lt;code&gt;ClassInfo&lt;/code&gt; leaking into Gradle), I know I can totally clean all the &lt;code&gt;ClassInfo&lt;/code&gt; references because I know I can shutdown the Groovy runtime, in the second case (Gradle &lt;code&gt;ClassInfo&lt;/code&gt; leaking), I basically have no idea that a class comes from the isolated classloader or not. So it&amp;#8217;s hard to say if you should remove the &lt;code&gt;ClassInfo&lt;/code&gt; or not. I am currently experimenting a brute force &quot;try to determine if a class belongs in the class loader hierarchy&quot;, but it is weak (ah ah!) because I need to know about several potential class loader types.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_whats_next&quot;&gt;What&amp;#8217;s next?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, what can we do next? One has to remember that fixing Groovy is not the ultimate solution because Gradle uses Groovy internally, but the various tasks can very well use a different Groovy version which is beyond our control.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;rollback Groovy in Gradle to use Groovy 2.3.10. It would avoid the Groovy classes from Gradle to leak into the Isolated classloaders, but is also unfortunate given the improvements that this version provides. Also, those who write Groovy applications for Android use Groovy 2.4+&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://codenarc.sourceforge.net/&quot;&gt;CodeNarc&lt;/a&gt; would still use Groovy 2.4+, we could downgrade it too. However, if people rely on features of Groovy 2.4+, they just have no choice, so we would still have the problem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use smarter techniques like instrumentation to track the leakages of &lt;code&gt;ClassInfo&lt;/code&gt;, record them, and revert when we&amp;#8217;re done. It&amp;#8217;s doable, but it&amp;#8217;s a huge amount of work, and relying on instrumentation for Gradle would be very bad for performance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Update Gradle to use FilteringClassLoader everywhere, including in its main process, to prevent &lt;code&gt;ClassValue&lt;/code&gt; to be found. This would work because without that class, Groovy wouldn&amp;#8217;t use &lt;code&gt;ClassValue&lt;/code&gt; to store the metadata and fall back to the old mechanism.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait for a fix in Groovy. Jochen is already working on that, but we know that the old mechanism isn&amp;#8217;t perfect either, and has memory leaks too. That was one of the reasons to migrate to &lt;code&gt;ClassValue&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wait for a fix of the JVM. That&amp;#8217;s beyond our control.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Increase the PermGen space for builds that use the code quality plugins, which internally use AntBuilder. It&amp;#8217;s what we do today. It works, but it&amp;#8217;s just hiding the problem. And we have to explain to our users to do it too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some smart people come with a smart solution, that&amp;#8217;s why I wrote this too. During that week, I got help from lots of people, including Jochen &quot;Groovy&quot; Theodorou, Henri &quot;EasyMock&quot; Tremblay, David Gageot or Nikita Salnikov from Plumbr, thank you guys!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By the way, if you wonder, the same problem exist in JDK 8 too, it&amp;#8217;s just not visible immediately because of the metaspace that appeared to replace the PermGen space.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, it was fun writing this &quot;post-mortem&quot;, I hope it wasn&amp;#8217;t too obscure, it helped me a lot because I had so many &quot;got it&quot; and &quot;oh noes!&quot; moments that I felt it was very interesting to share this story with you. And if you like technical challenges, do not forget that &lt;a href=&quot;https://gradle.org/gradle-jobs/&quot;&gt;Gradle is hiring&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After writing this post, I made great progress, and I did manage to get rid of the leak, but I also discovered that the leak happens with the various &lt;code&gt;GroovyCompile&lt;/code&gt;
tasks&amp;#8230;&amp;#8203; Anyway you can follow my progress on &lt;a href=&quot;https://github.com/gradle/gradle/tree/cc-oom-codenarc&quot;&gt;this branch&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Improved sandboxing of Groovy scripts</title>
      <link>https://melix.github.io/blog//2015/03/sandboxing.html</link>
      <pubDate>Fri, 27 Mar 2015 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2015/03/sandboxing.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the most current uses cases of Groovy is scripting. Groovy makes it very easy to execute code dynamically, at runtime. Depending
on the application, scripts can be found in multiple sources: file system, databases, remote services, &amp;#8230;&amp;#8203; but more importantly, the
designer of the application which executes scripts is not necessarily the one writing those scripts. Moreover, the scripts might run in a
constrained environment (limited memory, file descriptors, time, &amp;#8230;&amp;#8203;) or your you simply don&amp;#8217;t want to allow users to access the full
capabilities of the language from a script.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;openblock INFO&quot;&gt;
&lt;div class=&quot;title&quot;&gt;What you will learn in this post&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;why Groovy is a good fit to write internal DSLs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;what it implies in terms of security in your applications&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how you can customize compilation to improve the DSL&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the meaning of &lt;code&gt;SecureASTCustomizer&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;what are type checking extensions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how you can rely on type checking extensions to offer proper sandboxing&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, imagine that you want to offer users the ability to evaluate mathematical expressions. One option would be to implement your
own internal DSL, create a parser and eventually an interpreter for those expressions. Obviously this involves a bit of work, but if in
the end you need to improve performance, for example by generating bytecode for the expressions instead of evaluating them, or introduce
caching of those runtime generated classes, then Groovy is probably a very good option.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are lots of options available, described in the &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/index.html#_integrating_groovy_in_a_java_application&quot;&gt;documentation&lt;/a&gt;
but the most simple example is just using the &lt;code&gt;Eval&lt;/code&gt; class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Example.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;int sum = (Integer) Eval.me(&quot;1+1&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code &lt;code&gt;1+1&lt;/code&gt; is parsed, compiled to bytecode, loaded and eventually executed by Groovy at runtime. Of course in this example the code is very simple, and you will want to
add parameters, but the idea is that the code which is executed here is arbitrary. This is probably not what you want. For a calculator, you want to allow expressions like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;1+1
x+y
1+(2*x)**y
cos(alpha)*r
v=1+x&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;but certainly not&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;println &apos;Hello&apos;
(0..100).each { println &apos;Blah&apos; }
Pong p = new Pong()
println(new File(&apos;/etc/passwd&apos;).text)
System.exit(-1)
Eval.me(&apos;System.exit(-1)&apos;) // a script within a script!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is where things start to become complicated, and where we start seeing actually multiple needs:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;restricting the grammar of the language to a subset of its capabilities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;preventing users from executing unexpected code&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;preventing users from executing malicious code&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The calculator example is pretty simple, but for more complex DSLs, people might actually start writing problematic code without noticing, especially if the DSL is suffiently elegant to be used
by &lt;em&gt;non developers&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I was in this situation a few years ago, when I designed an engine that used Groovy &quot;scripts&quot; written by linguists. One of the problems was that they could unintentionally create infinite loops,
for example. Code was executing on the server, and then you had a thread eating 100% of the CPU and had no choice but restart the application server so I had to find a way to mitigate that
problem without compromising the DSL nor the tooling or the performance of the application.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Actually, lots of people have similar needs. During the past 4 years, I spoke to tons of users who had a similar question: &lt;em&gt;How can I prevent users from doing bad things in Groovy scripts?&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_compilation_customizers&quot;&gt;Compilation customizers&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At that time, I had implemented my own solution, but I knew that other people also had implemented similar ones. In the end, Guillaume Laforge
suggested to me that I wrote something that would help fixing those issues and make into Groovy core. This happened in Groovy 1.8.0 with
&lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/index.html#compilation-customizers&quot;&gt;compilation customizers&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Compilation customizers are a set of classes that are aimed at tweaking the compilation of Groovy scripts. You can write your own customizer but Groovy ships with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;an import customizer, which aims at adding imports transparently to scripts, so that users do not have to add &quot;import&quot; statements&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an AST (Abstract Syntax Tree) transformation customizer, which allows to add AST transformations transparently to scripts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a secure AST customizer, which aims at restricting the grammar and syntactical constructs of the language&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The AST transformation customizer allowed me to solve the infinite loop issue, by applying the &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/ThreadInterrupt.html&quot;&gt;@ThreadInterrupt&lt;/a&gt;
transformation, but the &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/api/org/codehaus/groovy/control/customizers/SecureASTCustomizer.html&quot;&gt;SecureASTCustomizer&lt;/a&gt; is probably the one which has
been the most misinterpreted of the whole.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I must apologize for this. Back then, I had no better name in mind. The important part of SecureASTCustomizer is &lt;strong&gt;AST&lt;/strong&gt;. It was aimed at restricting access to some features of the AST. The
&quot;secure&quot; part is actually not a good name at all, and I will illustrate why. You can even find a blog post from Kohsuke Kawagushi, of Jenkins fame, named
Groovy SecureASTCustomizer is harmful[&lt;a href=&quot;https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/&quot; class=&quot;bare&quot;&gt;https://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/&lt;/a&gt;]. It is very true. The SecureASTCustomizer has never been designed with sandboxing
in mind. It was designed to restrict the language at compile time, not runtime. So a much better name, in retrospect, would have been &lt;em&gt;GrammarCustomizer&lt;/em&gt;. But as you&amp;#8217;re certainly aware, there
are two hard things in computer science: cache invalidation, naming things and off by one errors.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So imagine that you think of the secure AST customizer as a way of securing your script, and that you want to use this to prevent a user from calling &lt;code&gt;System.exit&lt;/code&gt; from a script. The
documentation says that you can prevent calls on some specific receivers by defining either a blacklist or a whitelist. In terms of securing something, I would always recommand to use a
whitelist, that is to say to list explicitly what is allowed, rather than a blacklist, saying what is disallowed. The reason is that hackers always think of things you don&amp;#8217;t, so let&amp;#8217;s illustrate
this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here is how a naive &quot;sandbox&quot; script engine could be configured using the &lt;code&gt;SecureASTCustomizer&lt;/code&gt;. I am writing the examples of configuration in Java, even though I could write them in Groovy, just
to make the difference between the integration code and the scripts clear.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class Sandbox {
    public static void main(String[] args)  {
        CompilerConfiguration conf = new CompilerConfiguration();				&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
        SecureASTCustomizer customizer = new SecureASTCustomizer();				&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
        customizer.setReceiversBlackList(Arrays.asList(System.class.getName()));		&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
        conf.addCompilationCustomizers(customizer);						&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
        GroovyShell shell = new GroovyShell(conf);						&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
        Object v = shell.evaluate(&quot;System.exit(-1)&quot;);						&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
        System.out.println(&quot;Result = &quot; +v);							&lt;i class=&quot;conum&quot; data-value=&quot;7&quot;&gt;&lt;/i&gt;&lt;b&gt;(7)&lt;/b&gt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;create a compiler configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;create a secure AST customizer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;declare that the &lt;code&gt;System&lt;/code&gt; class is blacklisted as the receiver of method calls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;add the customizer to the compiler configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;associate the configuration to the script shell, that is, try to create a sandbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;execute a nasty script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;7&quot;&gt;&lt;/i&gt;&lt;b&gt;7&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;print the result of the execution of the script&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you run this class, when the script is executed, it will throw an error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;General error during canonicalization: Method calls not allowed on [java.lang.System]
java.lang.SecurityException: Method calls not allowed on [java.lang.System]&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the result of the application of the secure AST customizer, which prevents the execution of methods on the &lt;code&gt;System&lt;/code&gt; class. Success! Now we have secured our script! Oh wait&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_secureastcustomizer_pwned&quot;&gt;SecureASTCustomizer pwned!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Secure you say? So what if I do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def c = System
c.exit(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Execute again and you will see that the program exits &lt;strong&gt;without&lt;/strong&gt; error and &lt;strong&gt;without&lt;/strong&gt; printing the result. The return code of the process is -1, which indicates that the user script has been executed!
What happened? Basically, at compile time, the secure AST customizer is not able to recognize that &lt;code&gt;c.exit&lt;/code&gt; is a call on &lt;code&gt;System&lt;/code&gt;, because it works at the AST level! It analyzes a method call, and
in this case the method call is &lt;code&gt;c.exit(-1)&lt;/code&gt;, then gets the receiver and checks if the receiver is in the whitelist (or blacklist). In this case, the receiver is &lt;code&gt;c&lt;/code&gt; and this variable is &lt;strong&gt;declared
with def&lt;/strong&gt;, which is equivalent to declaring it as &lt;code&gt;Object&lt;/code&gt;, so it will think that &lt;code&gt;c&lt;/code&gt; is &lt;code&gt;Object&lt;/code&gt;, not &lt;code&gt;System&lt;/code&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Actually there are &lt;strong&gt;many&lt;/strong&gt; ways to workaround the various configurations that you can make on the secure AST customizer. Just for fun, a few of them:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;((Object)System).exit(-1)
Class.forName(&apos;java.lang.System&apos;).exit(-1)
(&apos;java.lang.System&apos; as Class).exit(-1)

import static java.lang.System.exit
exit(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and there are &lt;strong&gt;much&lt;/strong&gt; more options. The dynamic nature of Groovy just makes it impossible to resolve those cases at compile time. There are solutions though. One option is to rely on the JVM standard
security manager. However this is a system wide solution which is often considered as a hammer. But it also doesn&amp;#8217;t really work for all cases, for example you might not want to prevent creation of
files, but only reads for example&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This limitation - or should I say frustration for lots of us - led several people to create a solution based on &lt;strong&gt;runtime checks&lt;/strong&gt;. Runtime checks do not suffer the same problem, because you
will have for example the actual receiver type of a message before checking if a method call is allowed or not. In particular, those implementations are of particular interest:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/jimwhite/Gondor/blob/master/src/org/ifcx/gondor/SecuredScript.java&quot;&gt;SecureScript&lt;/a&gt; by Jim White&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://groovy-sandbox.kohsuke.org/&quot;&gt;Groovy Sandbox&lt;/a&gt; by Kohsuke Kawagushi&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/simon-temple/groovy-sandbox&quot;&gt;Groovy Sandbox&lt;/a&gt; by Simon Temple&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However none of those implementations is totally secure or reliable. For example, the version by Kohsuke relies on hacking the internal implementation of call site caching. The problem is that it is
not compatible with the invokedynamic version of Groovy, and those internal classes are going to be removed in future versions of Groovy. The version by Simon, on the other hand, relies on AST transformations
but misses a lot of possible hacks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a result, with friends of mine Corinne Krych, Fabrice Matrat and Sébastien Blanc, we decided to create a new runtime sandboxing mechanism that would not have the issues of those projects. We started
implementing this during a hackathon in Nice, and &lt;a href=&quot;https://greachconf.com/speakers/fabrice-matrat-cedric-champeau-groovy-head-in-the-cloud/&quot;&gt;we gave a talk about this last year&lt;/a&gt; at the Greach conference.
It relies on AST transformations and heavily rewrites the code in order to perform a check before each method call, property access, increment of variable, binary expression, &amp;#8230;&amp;#8203;
The &lt;a href=&quot;https://github.com/rivieragug/groovy-core/tree/secureruntime&quot;&gt;implementation&lt;/a&gt; is still incomplete, and not much work has been done because I realized there was still a problem in case
of methods or properties called on &quot;implicit this&quot;, like in builders for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;xml {
   cars {				 // cars is a method call on an implicit this: &quot;this&quot;.cars(...)
     car(make:&apos;Renault&apos;, model: &apos;Clio&apos;)
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As of today I still didn&amp;#8217;t find a way to properly handle this because of the design of the meta-object protocol in Groovy, that here relies on the fact that a receiver throws an exception when the method
is not found before trying another receiver. In short, it means that you cannot know the type of the receiver before the method is actually called. And if it is called, it&amp;#8217;s already too late&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Until earlier this year I had still no perfect solution to this problem, in case the script being executed is using the dynamic features of the language. But now has come the time to explain how you can
significantly improve the situation if you are ready to loose some of the dynamism of the language.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_type_checking&quot;&gt;Type checking&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s come back to the root problem of the SecureASTCustomizer: it works on the abstract syntax tree and has no knowledge of the concrete types of the receivers of messages. But since Groovy 2, Groovy has
optional compilation, and in Groovy 2.1, we added &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/#_type_checking_extensions&quot;&gt;type checking extensions&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Type checking extensions are very powerful: they allow the designer of a Groovy DSL to help the compiler infer types, but it also lets you throw compilation errors when normally it should not. Type
checking extensions are even used internally in Groovy to support the static compiler, for example to implement traits or the
&lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What if, instead of relying on the information available after parsing, we could rely on information from the type checker? Take the following code that our hacker tried to write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;((Object)System).exit(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you activate type checking, this code would not compile:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;1 compilation error:

[Static type checking] - Cannot find matching method java.lang.Object#exit(java.lang.Integer). Please check if the declared type is right and if the method exists.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So this code would not compile anymore. But what if the code is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def c = System
c.exit(-1)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can verify that this passes type checking by wrapping the code into a method and running the script with the &lt;code&gt;groovy&lt;/code&gt; command line tool:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@groovy.transform.TypeChecked // or even @CompileStatic
void foo() {
  def c = System
  c.exit(-1)
}
foo()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the type checker will recognize that the &lt;code&gt;exit&lt;/code&gt; method is called on the &lt;code&gt;System&lt;/code&gt; class and is valid. It will not help us there. But what we know, if this code passes type checking, is that the
compiler recognized the call on the &lt;code&gt;System&lt;/code&gt; receiver. The idea, then, is to rely on a type checking extension to disallow the call.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_simple_type_checking_extension&quot;&gt;A simple type checking extension&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before we dig into the details about sandboxing, let&amp;#8217;s try to &quot;secure&quot; our script using a traditional type checking extension. Registering a type checking extension is easy: just set the &lt;code&gt;extensions&lt;/code&gt;
parameter of the &lt;code&gt;@TypeChecked&lt;/code&gt; annotation (or &lt;code&gt;@CompileStatic&lt;/code&gt; if you want to use static compilation):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@TypeChecked(extensions=[&apos;SecureExtension1.groovy&apos;])
void foo() {
  def c = System
  c.exit(-1)
}
foo()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The extension will be searched on classpath in source form (there&amp;#8217;s an option to have precompiled type checking extensions but this is beyond the scope of this blog post):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;SecureExtension1.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;onMethodSelection { expr, methodNode -&amp;gt;					&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
   if (methodNode.declaringClass.name==&apos;java.lang.System&apos;) {		&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
      addStaticTypeError(&quot;Method call is not allowed!&quot;, expr)		&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;when the type checker selects the target method of a call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;then if the selected method belongs to the &lt;code&gt;System&lt;/code&gt; class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;make the type checker throw an error&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s really all needed. Now execute the code again, and you will see that there&amp;#8217;s a compile time error!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;/home/cchampeau/tmp/securetest.groovy: 6: [Static type checking] - Method call is not allowed!
 @ line 6, column 3.
     c.exit(-1)
     ^

1 error&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So this time, thanks to the type checker, &lt;code&gt;c&lt;/code&gt; is really recognized as an instance of class &lt;code&gt;System&lt;/code&gt; and we can really disallow the call. This is a very simple example, but it doesn&amp;#8217;t really go as
far as what we can do with the secure AST customizer in terms of configuration. The extension that we wrote has &lt;strong&gt;hardcoded&lt;/strong&gt; checks, but it would probably be nicer if we could configure it. So let&amp;#8217;s
start working with a bit more complex example.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine that your application computes a score for a document and that you allow the users to customize the score. Then your DSL:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;will expose (at least) a variable named &lt;code&gt;score&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;will allow the user to perform mathematical operations (including calling methods like &lt;em&gt;cos&lt;/em&gt;, &lt;em&gt;abs&lt;/em&gt;, &amp;#8230;&amp;#8203;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;should disallow all other method calls&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;An example of user script would be:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;abs(cos(1+score))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Such a DSL is easy to setup. It&amp;#8217;s a variant of the one we defined earlier:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Sandbox.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;CompilerConfiguration conf = new CompilerConfiguration();
ImportCustomizer customizer = new ImportCustomizer();
customizer.addStaticStars(&quot;java.lang.Math&quot;);                        &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
conf.addCompilationCustomizers(customizer);
Binding binding = new Binding();
binding.setVariable(&quot;score&quot;, 2.0d);                                 &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
GroovyShell shell = new GroovyShell(binding,conf);
Double userScore = (Double) shell.evaluate(&quot;abs(cos(1+score))&quot;);    &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
System.out.println(&quot;userScore = &quot; + userScore);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;add an import customizer that will add &lt;code&gt;import static java.lang.Math.*&lt;/code&gt; to all scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;make the &lt;code&gt;score&lt;/code&gt; variable available to the script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;execute the script&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock tip&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-tip&quot; title=&quot;Tip&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
There are options to cache the scripts, instead of parsing and compiling them each time. Please check the documentation for more details.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So far, our script works, but nothing prevents a hacker from executing malicious code. Since we want to use type checking, I would recommand to use the &lt;code&gt;@CompileStatic&lt;/code&gt; transformation
transparently:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it will activate type checking on the script, and we will be able to perform additional checks thanks to the type checking extension&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it will improve the performance of the script&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Adding &lt;code&gt;@CompileStatic&lt;/code&gt; transparently is easy. We just have to update the compiler configuration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;ASTTransformationCustomizer astcz = new ASTTransformationCustomizer(CompileStatic.class);
conf.addCompilationCustomizers(astcz);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now if you try to execute the script again, you will face a compile time error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Script1.groovy: 1: [Static type checking] - The variable [score] is undeclared.
 @ line 1, column 11.
   abs(cos(1+score))
             ^

Script1.groovy: 1: [Static type checking] - Cannot find matching method int#plus(java.lang.Object). Please check if the declared type is right and if the method exists.
 @ line 1, column 9.
   abs(cos(1+score))
           ^

2 errors&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What happened? If you read the script from a &quot;compiler&quot; point of view, it doesn&amp;#8217;t know anything about the &quot;score&quot; variable. &lt;strong&gt;You&lt;/strong&gt;, as a developer, know that it&amp;#8217;s a variable
of type &lt;code&gt;double&lt;/code&gt;, but the compiler cannot infer it. This is precisely what type checking extensions are designed for: you can provide additional information to the compiler,
so that compilation passes. In this case, we will want to indicate that the &lt;code&gt;score&lt;/code&gt; variable is of type &lt;code&gt;double&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So we will slightly change the way we transparently add the &lt;code&gt;@CompileStatic&lt;/code&gt; annotation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;ASTTransformationCustomizer astcz = new ASTTransformationCustomizer(
        singletonMap(&quot;extensions&quot;, singletonList(&quot;SecureExtension2.groovy&quot;)),
        CompileStatic.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This will &quot;emulate&quot; code annotated with &lt;code&gt;@CompileStatic(extensions=[&apos;SecureExtension2.groovy&apos;])&lt;/code&gt;. Of course now we need to write the extension which will recognize the &lt;code&gt;score&lt;/code&gt; variable:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;SecureExtension2.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;unresolvedVariable { var -&amp;gt;			&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
   if (var.name==&apos;score&apos;) {			&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
      return makeDynamic(var, double_TYPE)	&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;in case the type checker cannot resolve a variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if the variable name is &lt;code&gt;score&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;then instruct the compiler to resolve the variable dynamically, and that the type of the variable is &lt;code&gt;double&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can find a complete description of the type checking extension DSL in &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/#&quot; class=&quot;bare&quot;&gt;https://docs.groovy-lang.org/latest/html/documentation/#&lt;/a&gt;&lt;em&gt;type_checking_extensions[this section of the documentation],
but you have here an example of _mixed mode compilation&lt;/em&gt; : the compiler is not able to resolve the &lt;code&gt;score&lt;/code&gt; variable. You, as the designer of the DSL, &lt;strong&gt;know&lt;/strong&gt; that the variable is in fact
found in the binding, and is of the &lt;code&gt;double&lt;/code&gt;, so the &lt;code&gt;makeDynamic&lt;/code&gt; call is here to tell the compiler: &quot;ok, don&amp;#8217;t worry, I know what I am doing, this variable can be resolved dynamically
and it will be of type `double`&quot;. That&amp;#8217;s it!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_first_completed_secure_extension&quot;&gt;First completed &quot;secure&quot; extension&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now it&amp;#8217;s time to put this altogether. We wrote a type checking extension which is capable of preventing calls on &lt;code&gt;System&lt;/code&gt; on one side, and we wrote another which is able to resolve the &lt;code&gt;score&lt;/code&gt;
variable on another. So if we combine both, we have a first, complete, securing type checking extension:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;SecureExtension3.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;// disallow calls on System
onMethodSelection { expr, methodNode -&amp;gt;
    if (methodNode.declaringClass.name==&apos;java.lang.System&apos;) {
        addStaticTypeError(&quot;Method call is not allowed!&quot;, expr)
    }
}

// resolve the score variable
unresolvedVariable { var -&amp;gt;
    if (var.name==&apos;score&apos;) {
        return makeDynamic(var, double_TYPE)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Don&amp;#8217;t forget to update the configuration in your Java class to use the new type checking extension:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;ASTTransformationCustomizer astcz = new ASTTransformationCustomizer(
        singletonMap(&quot;extensions&quot;, singletonList(&quot;SecureExtension3.groovy&quot;)),
	CompileStatic.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Execute the code again and it still works. Now, try to do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;abs(cos(1+score))
System.exit(-1)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And the script compilation will fail with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Script1.groovy: 1: [Static type checking] - Method call is not allowed!
 @ line 1, column 19.
   abs(cos(1+score));System.exit(-1)
                     ^

1 error&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Congratulations, you just wrote your first type checking extension that prevents the execution of malicious code!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_improving_configuration_of_the_extension&quot;&gt;Improving configuration of the extension&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So far so good, we are able to prevent calls on &lt;code&gt;System&lt;/code&gt;, but it is likely that we are going to discover new vulnerabilities, and that we will want to
prevent execution of such code. So instead of hardcoding everything in the extension, we will try to make our extension generic and configurable. This is
probably the trickiest thing to do, because there&amp;#8217;s no direct way to provide context to a type checking extension. Our idea therefore relies on the (ugly)
thread locals to pass configuration data to the type checker.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first thing we&amp;#8217;re going to do is to make the variable list configurable. Here is the code on the Java side of things:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Sandbox.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class Sandbox {
    public static final String VAR_TYPES = &quot;sandboxing.variable.types&quot;;

    public static final ThreadLocal&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; COMPILE_OPTIONS = new ThreadLocal&amp;lt;&amp;gt;();		&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;

    public static void main(String[] args) {
        CompilerConfiguration conf = new CompilerConfiguration();
        ImportCustomizer customizer = new ImportCustomizer();
        customizer.addStaticStars(&quot;java.lang.Math&quot;);
        ASTTransformationCustomizer astcz = new ASTTransformationCustomizer(
                singletonMap(&quot;extensions&quot;, singletonList(&quot;SecureExtension4.groovy&quot;)),			&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
                CompileStatic.class);
        conf.addCompilationCustomizers(astcz);
        conf.addCompilationCustomizers(customizer);

        Binding binding = new Binding();
        binding.setVariable(&quot;score&quot;, 2.0d);
        try {
            Map&amp;lt;String,ClassNode&amp;gt; variableTypes = new HashMap&amp;lt;String, ClassNode&amp;gt;();			&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
            variableTypes.put(&quot;score&quot;, ClassHelper.double_TYPE);					&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
            Map&amp;lt;String,Object&amp;gt; options = new HashMap&amp;lt;String, Object&amp;gt;();					&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
            options.put(VAR_TYPES, variableTypes);							&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;
            COMPILE_OPTIONS.set(options);								&lt;i class=&quot;conum&quot; data-value=&quot;7&quot;&gt;&lt;/i&gt;&lt;b&gt;(7)&lt;/b&gt;
            GroovyShell shell = new GroovyShell(binding, conf);
            Double userScore = (Double) shell.evaluate(&quot;abs(cos(1+score));System.exit(-1)&quot;);
            System.out.println(&quot;userScore = &quot; + userScore);
        } finally {
            COMPILE_OPTIONS.remove();									&lt;i class=&quot;conum&quot; data-value=&quot;8&quot;&gt;&lt;/i&gt;&lt;b&gt;(8)&lt;/b&gt;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;create a &lt;code&gt;ThreadLocal&lt;/code&gt; that will hold the contextual configuration of the type checking extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;update the extension to &lt;code&gt;SecureExtension4.groovy&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;variableTypes&lt;/code&gt; is a map variable name &amp;#8594; variable type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;so this is where we&amp;#8217;re going to add the &lt;code&gt;score&lt;/code&gt; variable declaration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;options&lt;/code&gt; is the map that will store our type checking configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we set the &quot;variable types&quot; value of this configuration map to the map of variable types&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;7&quot;&gt;&lt;/i&gt;&lt;b&gt;7&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;and assign it to the thread local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;8&quot;&gt;&lt;/i&gt;&lt;b&gt;8&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;eventually, to avoid memory leaks, it is important to remove the configuration from the thread local&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And now, here is how the type checking extension can use this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import static Sandbox.*

def typesOfVariables = COMPILE_OPTIONS.get()[VAR_TYPES]				&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;

unresolvedVariable { var -&amp;gt;
    if (typesOfVariables[var.name]) {						&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
        return makeDynamic(var, typesOfVariables[var.name])			&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Retrieve the list of variable types from the thread local&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if an unresolved variable is found in the map of known variables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;then declare to the type checker that the variable is of the type found in the map&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Basically, the type checking extension, because it is executed when the type checker verifies the script, can access the
configuration through the thread local. Then, instead of using hard coded names in &lt;code&gt;unresolvedVariable&lt;/code&gt;, we can just check
that the variable that the type checker doesn&amp;#8217;t know about is actually declared in the configuration. If it is, then we
can tell it which type it is. Easy!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now we have to find a way to explicitly declare the list of allowed method calls. It is a bit trickier to find a proper
configuration for that, but here is what we came up with.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_configuring_a_white_list_of_methods&quot;&gt;Configuring a white list of methods&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea of the whitelist is simple. A method call will be allowed if the method descriptor can be found in the whitelist. This whitelist consists of regular expressions, and
the method descriptor consists of the fully-qualified class name of the method, it&amp;#8217;s name and parameters. For example, for &lt;code&gt;System.exit&lt;/code&gt;, the descriptor would be:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;java.lang.System#exit(int)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So let&amp;#8217;s see how to update the Java integration part to add this configuration:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class Sandbox {
    public static final String WHITELIST_PATTERNS = &quot;sandboxing.whitelist.patterns&quot;;

    // ...

    public static void main(String[] args) {
        // ...
        try {
            Map&amp;lt;String,ClassNode&amp;gt; variableTypes = new HashMap&amp;lt;String, ClassNode&amp;gt;();
            variableTypes.put(&quot;score&quot;, ClassHelper.double_TYPE);
            Map&amp;lt;String,Object&amp;gt; options = new HashMap&amp;lt;String, Object&amp;gt;();
            List&amp;lt;String&amp;gt; patterns = new ArrayList&amp;lt;String&amp;gt;();					&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
            patterns.add(&quot;java\\.lang\\.Math#&quot;);						&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
            options.put(VAR_TYPES, variableTypes);
            options.put(WHITELIST_PATTERNS, patterns);						&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
            COMPILE_OPTIONS.set(options);
            GroovyShell shell = new GroovyShell(binding, conf);
            Double userScore = (Double) shell.evaluate(&quot;abs(cos(1+score));System.exit(-1)&quot;);
            System.out.println(&quot;userScore = &quot; + userScore);
        } finally {
            COMPILE_OPTIONS.remove();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;declare a list of patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;add all methods of &lt;code&gt;java.lang.Math&lt;/code&gt; as allowed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;put the whitelist to the type checking options map&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then on the type checking extension side:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.MethodNode
import org.codehaus.groovy.ast.Parameter
import org.codehaus.groovy.transform.stc.ExtensionMethodNode

import static Sandbox.*

@CompileStatic
private static String prettyPrint(ClassNode node) {
    node.isArray()?&quot;${prettyPrint(node.componentType)}[]&quot;:node.toString(false)
}

@CompileStatic
private static String toMethodDescriptor(MethodNode node) {								&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    if (node instanceof ExtensionMethodNode) {
        return toMethodDescriptor(node.extensionMethodNode)
    }
    def sb = new StringBuilder()
    sb.append(node.declaringClass.toString(false))
    sb.append(&quot;#&quot;)
    sb.append(node.name)
    sb.append(&apos;(&apos;)
    sb.append(node.parameters.collect { Parameter it -&amp;gt;
        prettyPrint(it.originType)
    }.join(&apos;,&apos;))
    sb.append(&apos;)&apos;)
    sb
}
def typesOfVariables = COMPILE_OPTIONS.get()[VAR_TYPES]
def whiteList = COMPILE_OPTIONS.get()[WHITELIST_PATTERNS]								&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;

onMethodSelection { expr, MethodNode methodNode -&amp;gt;
    def descr = toMethodDescriptor(methodNode)										&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
    if (!whiteList.any { descr =~ it }) {										&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
        addStaticTypeError(&quot;You tried to call a method which is not allowed, what did you expect?: $descr&quot;, expr)	&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
    }
}

unresolvedVariable { var -&amp;gt;
    if (typesOfVariables[var.name]) {
        return makeDynamic(var, typesOfVariables[var.name])
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;this method will generate a method descriptor from a &lt;code&gt;MethodNode&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;retrieve the whitelist of methods from the thread local option map&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;convert a selected method into a descriptor string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if the descriptor doesn&amp;#8217;t match any of the whitelist entries, throw an error&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So if you execute the code again, you will now have a very cool error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Script1.groovy: 1: [Static type checking] - You tried to call a method which is not allowed, what did you expect?: java.lang.System#exit(int)
 @ line 1, column 19.
   abs(cos(1+score));System.exit(-1)
                     ^

1 error&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There we are! We now have a type checking extension which handles both the types of the variables that you export in the binding &lt;strong&gt;and&lt;/strong&gt;
a whitelist of allowed methods. This is still not perfect, but we&amp;#8217;re very close to the final solution! It&amp;#8217;s not perfect because we only
took care of method calls here, but you have to deal with more than that. For example, properties (like &lt;code&gt;foo.text&lt;/code&gt; which is implicitly
converted into &lt;code&gt;foo.getText()&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_putting_it_altogether&quot;&gt;Putting it altogether&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dealing with properties is a bit more complicated because the type checker doesn&amp;#8217;t have a handler for &quot;property selection&quot; like it does
for methods. We can work around that, and if you are interested in seeing the resulting code, check it out below. It&amp;#8217;s
a type checking extension which is not written exactly as you have seen in this blog post, because it is meant to be precompiled
for improved performance. But the idea is exactly the same.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;SandboxingTypeCheckingExtension.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ClassCodeVisitorSupport
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.ast.MethodNode
import org.codehaus.groovy.ast.Parameter
import org.codehaus.groovy.ast.expr.PropertyExpression
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys
import org.codehaus.groovy.transform.stc.ExtensionMethodNode
import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport
import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport

import static Sandbox.*

class SandboxingTypeCheckingExtension extends GroovyTypeCheckingExtensionSupport.TypeCheckingDSL {

    @CompileStatic
    private static String prettyPrint(ClassNode node) {
        node.isArray()?&quot;${prettyPrint(node.componentType)}[]&quot;:node.toString(false)
    }

    @CompileStatic
    private static String toMethodDescriptor(MethodNode node) {
        if (node instanceof ExtensionMethodNode) {
            return toMethodDescriptor(node.extensionMethodNode)
        }
        def sb = new StringBuilder()
        sb.append(node.declaringClass.toString(false))
        sb.append(&quot;#&quot;)
        sb.append(node.name)
        sb.append(&apos;(&apos;)
        sb.append(node.parameters.collect { Parameter it -&amp;gt;
            prettyPrint(it.originType)
        }.join(&apos;,&apos;))
        sb.append(&apos;)&apos;)
        sb
    }

    @Override
    Object run() {

        // Fetch white list of regular expressions of authorized method calls
        def whiteList = COMPILE_OPTIONS.get()[WHITELIST_PATTERNS]
        def typesOfVariables = COMPILE_OPTIONS.get()[VAR_TYPES]

        onMethodSelection { expr, MethodNode methodNode -&amp;gt;
            def descr = toMethodDescriptor(methodNode)
            if (!whiteList.any { descr =~ it }) {
                addStaticTypeError(&quot;You tried to call a method which is not allowed, what did you expect?: $descr&quot;, expr)
            }
        }

        unresolvedVariable { var -&amp;gt;
            if (isDynamic(var) &amp;amp;&amp;amp; typesOfVariables[var.name]) {
                storeType(var, typesOfVariables[var.name])
                handled = true
            }
        }

        // handling properties (like foo.text) is harder because the type checking extension
        // does not provide a specific hook for this. Harder, but not impossible!

        afterVisitMethod { methodNode -&amp;gt;
            def visitor = new PropertyExpressionChecker(context.source, whiteList)
            visitor.visitMethod(methodNode)
        }
    }

    private class PropertyExpressionChecker extends ClassCodeVisitorSupport {
        private final SourceUnit unit
        private final List&amp;lt;String&amp;gt; whiteList

        PropertyExpressionChecker(final SourceUnit unit, final List&amp;lt;String&amp;gt; whiteList) {
            this.unit = unit
            this.whiteList = whiteList
        }

        @Override
        protected SourceUnit getSourceUnit() {
            unit
        }

        @Override
        void visitPropertyExpression(final PropertyExpression expression) {
            super.visitPropertyExpression(expression)

            ClassNode owner = expression.objectExpression.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER)
            if (owner) {
                if (expression.spreadSafe &amp;amp;&amp;amp; StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(owner, classNodeFor(Collection))) {
                    owner = typeCheckingVisitor.inferComponentType(owner, ClassHelper.int_TYPE)
                }
                def descr = &quot;${prettyPrint(owner)}#${expression.propertyAsString}&quot;
                if (!whiteList.any { descr =~ it }) {
                    addStaticTypeError(&quot;Property is not allowed: $descr&quot;, expression)
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And a final version of the sandbox that includes assertions to make sure that we catch all cases:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;Sandbox.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class Sandbox {
    public static final String WHITELIST_PATTERNS = &quot;sandboxing.whitelist.patterns&quot;;
    public static final String VAR_TYPES = &quot;sandboxing.variable.types&quot;;

    public static final ThreadLocal&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt; COMPILE_OPTIONS = new ThreadLocal&amp;lt;Map&amp;lt;String, Object&amp;gt;&amp;gt;();

    public static void main(String[] args) {
        CompilerConfiguration conf = new CompilerConfiguration();
        ImportCustomizer customizer = new ImportCustomizer();
        customizer.addStaticStars(&quot;java.lang.Math&quot;);
        ASTTransformationCustomizer astcz = new ASTTransformationCustomizer(
                singletonMap(&quot;extensions&quot;, singletonList(&quot;SandboxingTypeCheckingExtension.groovy&quot;)),
                CompileStatic.class);
        conf.addCompilationCustomizers(astcz);
        conf.addCompilationCustomizers(customizer);

        Binding binding = new Binding();
        binding.setVariable(&quot;score&quot;, 2.0d);
        try {
            Map&amp;lt;String, ClassNode&amp;gt; variableTypes = new HashMap&amp;lt;String, ClassNode&amp;gt;();
            variableTypes.put(&quot;score&quot;, ClassHelper.double_TYPE);
            Map&amp;lt;String, Object&amp;gt; options = new HashMap&amp;lt;String, Object&amp;gt;();
            List&amp;lt;String&amp;gt; patterns = new ArrayList&amp;lt;String&amp;gt;();
            // allow method calls on Math
            patterns.add(&quot;java\\.lang\\.Math#&quot;);
            // allow constructors calls on File
            patterns.add(&quot;File#&amp;lt;init&amp;gt;&quot;);
            // because we let the user call each/times/...
            patterns.add(&quot;org\\.codehaus\\.groovy\\.runtime\\.DefaultGroovyMethods&quot;);
            options.put(VAR_TYPES, variableTypes);
            options.put(WHITELIST_PATTERNS, patterns);
            COMPILE_OPTIONS.set(options);
            GroovyShell shell = new GroovyShell(binding, conf);
            Object result;
            try {
                result = shell.evaluate(&quot;Eval.me(&apos;1&apos;)&quot;); // error
                assert false;
            } catch (MultipleCompilationErrorsException e) {
                System.out.println(&quot;Successful sandboxing: &quot;+e.getMessage());
            }
            try {
                result = shell.evaluate(&quot;System.exit(-1)&quot;); // error
                assert false;
            } catch (MultipleCompilationErrorsException e) {
                System.out.println(&quot;Successful sandboxing: &quot;+e.getMessage());
            }
            try {
                result = shell.evaluate(&quot;((Object)Eval).me(&apos;1&apos;)&quot;); // error
                assert false;
            } catch (MultipleCompilationErrorsException e) {
                System.out.println(&quot;Successful sandboxing: &quot;+e.getMessage());
            }

            try {
                result = shell.evaluate(&quot;new File(&apos;/etc/passwd&apos;).getText()&quot;); // getText is not allowed
                assert false;
            } catch (MultipleCompilationErrorsException e) {
                System.out.println(&quot;Successful sandboxing: &quot;+e.getMessage());
            }

            try {
                result = shell.evaluate(&quot;new File(&apos;/etc/passwd&apos;).text&quot;);  // getText is not allowed
                assert false;
            } catch (MultipleCompilationErrorsException e) {
                System.out.println(&quot;Successful sandboxing: &quot;+e.getMessage());
            }

            Double userScore = (Double) shell.evaluate(&quot;abs(cos(1+score))&quot;);
            System.out.println(&quot;userScore = &quot; + userScore);
        } finally {
            COMPILE_OPTIONS.remove();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This post has explored the interest of using Groovy as a platform for scripting on the JVM. It introduced various mechanisms for integration, and showed that this
comes at the price of security. However, we illustrated some concepts like compilation customizers that make it easier to sandbox the environment of execution of
scripts. The current list of customizers available in the Groovy distribution, and the currently available sandboxing projects in the wild, are not sufficient
to guarantee security of execution of scripts in the general case (dependending, of course, on your users and where the scripts come from).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We then illustrated how you could, if you are ready to pay the price of loosing some of the dynamic features of the language, properly workaround those limitations
through type checking extensions. Those type checking extensions are so powerful that you can even introduce your own error messages during the compilation of
scripts. Eventually, by doing this and caching your scripts, you will also benefit from dramatic performance improvements in script execution.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, the sandboxing mechanism that we illustrated is &lt;strong&gt;not&lt;/strong&gt; a replacement for the &lt;code&gt;SecureASTCustomizer&lt;/code&gt;. We recommand that you actually use &lt;strong&gt;both&lt;/strong&gt;, because they
work on different levels: the secure AST customizer will work on the grammar level, allowing you to restrict some language constructs (for example preventing the
creation of closures or classes inside the script), while the type checking extension will work after type inference (allowing you to reason on inferred types
rather than declared types).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, the solution that I described here is incomplete. It is not available in Groovy core. As I will have less time to work on Groovy, I would be very
glad if someone or some people improve this solution and make a pull request so that we can have something!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Who is Groovy?</title>
      <link>https://melix.github.io/blog//2015/02/who-is-groovy.html</link>
      <pubDate>Wed, 4 Mar 2015 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2015/02/who-is-groovy.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With all the changes that the Groovy project is seeing since the beginning of the year, I thought it was a good time to
make a summary about its history. In particular, with the &lt;a href=&quot;https://blog.pivotal.io/pivotal/news-2/groovy-2-4-and-grails-3-0-to-be-last-major-releases-under-pivotal-sponsorship&quot;&gt;end of sponsorship from Pivotal&lt;/a&gt;, as well as
&lt;a href=&quot;https://restlet.com/blog/2015/03/02/head-of-groovy-project-joins-restlet-to-lead-api-development-tools/&quot;&gt;Guillaume Laforge annoucing he is joining Restlet&lt;/a&gt;, a lot of people state that Groovy is done. It will be the occasion to talk about
the history of the project, both in terms of community and sponsorship.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, Groovy is, and will remain, alive. Groovy is a community project and we are pleased to announce that &lt;strong&gt;&lt;a href=&quot;https://glaforge.appspot.com/article/groovy-projects-intends-to-join-the-apache-software-foundation&quot;&gt;Groovy
has started the process to join the Apache Software Foundation&lt;/a&gt;&lt;/strong&gt;. The community deserved it, and even if it will mean some adaptations on
our side, we think that the &lt;a href=&quot;https://apache.org&quot;&gt;ASF&lt;/a&gt; will be a great fit for the project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To build the statistics you will read in this post, I have used a &lt;a href=&quot;https://github.com/melix/blog/blob/master/src/jbake/content/2015/02/commit-stats.groovy&quot;&gt;Groovy script&lt;/a&gt; (of course!) that
takes as reference the number of commits. This is far from being a perfect number, because some commits are just
for fixing typos, while others are full new features and it also totally misses the fact that patches, before Git, didn&amp;#8217;t carry the author
information or the problem that we maintain multiple branches
of Groovy, requiring a lot of work, but it gives an idea&amp;#8230;&amp;#8203; And because people think that end of sponsorship
may be equivalent to death, I separated commits in two categories: sponsored and community. Sponsored commits are commits
which are likely to have been made by someone directly paid to contribute on Groovy. We will see how this proportion evolved
over time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you think Groovy is dead, please read the following carefully. Let&amp;#8217;s start our journey back in time!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2003_a_dynamic_language_for_the_jvm&quot;&gt;2003: A dynamic language for the JVM&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 476 commits &lt;strong&gt;Community&lt;/strong&gt;: 476 commits (100%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;James Strachan : 374 commits (78%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bob McWhirter : 76 commits (15%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sam Pullara : 23 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kasper Nielsen : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Aslak Hellesoy : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2003 is the inception year of Groovy. &lt;strong&gt;James Strachan&lt;/strong&gt;, in August 2003, wanted to create a dynamic language for the JVM, inspired by Ruby,
but closer to Java. Groovy was born, and the idea never changed over time: Groovy is the perfect companion for Java, a language which can
be very close to Java in terms of syntax but also removes a lot of its boilerplate. Bob McWhirter is a famous name in the JVM world, he is
now Director of Polyglot at Red Hat, so you can see that when he started contributing to the language back then, there was already a story
for him! Sam Pullara is another very smart guy in the JVM world and he worked for top companies like BEA, Yahoo! or Twitter to name a few.
He is a technical reviewer for the JavaOne conference.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2004_guillaume_laforge_joins_the_project&quot;&gt;2004: Guillaume Laforge joins the project&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 871 commits &lt;strong&gt;Community&lt;/strong&gt;: 871 commits (100%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;James Strachan : 495 commits (56%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge : 101 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wilson : 70 commits (8%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sam Pullara : 66 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeremy Rayner : 33 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chris Poirier : 28 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bing Ran : 21 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Steve Goetze : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Stump : 10 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zohar Melamed : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Damage Control : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bob McWhirter : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Christiaan ten Klooster : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yuri Schimke : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy is hosted at &lt;a href=&quot;https://www.codehaus.org/&quot;&gt;Codehaus&lt;/a&gt; (which just has annouced its retirement) and 2004 sees the appearance of famous names of the community. In particular,
you can already see &lt;strong&gt;Guillaume Laforge&lt;/strong&gt; and &lt;strong&gt;Jochen Theodorou&lt;/strong&gt;. Both of them still directly work on the project as today. John Wilson started contributing
the famous XML support of Groovy, and you can also note names like Russel Winder of Gant and &lt;a href=&quot;https://gpars.codehaus.org/&quot;&gt;GPars&lt;/a&gt; fame. Jeremy Rayer&amp;#8217;s work is famous in the Groovy
community since he wrote the first versions of the Groovy grammar using Antlr.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2005_jochen_theodorou_joins_the_project&quot;&gt;2005: Jochen Theodorou joins the project&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 934 commits &lt;strong&gt;Community&lt;/strong&gt;: 934 commits (100%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Jochen Theodorou : 244 commits (26%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;James Strachan : 162 commits (17%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pilho Kim : 104 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wilson : 79 commits (8%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge : 75 commits (8%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dierk Koenig : 70 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeremy Rayner : 62 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Christian Stein : 48 commits (5%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alan Green : 20 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 20 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin C. Martin : 14 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sam Pullara : 10 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Rose : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hein Meling : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scott Stirling : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Franck Rasolo : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I would tend to think that 2005 is the year when Jochen Theodorou took the technical lead of Groovy. In 2005, he becomes the most prolific contributor,
even beyond the creator of the language himself. Dierk Koenig makes an appearance here: he is known for his work on &lt;a href=&quot;https://gpars.codehaus.org/&quot;&gt;GPars&lt;/a&gt;, but also for the reference book for Groovy: &lt;a href=&quot;https://www.manning.com/koenig2/&quot;&gt;Groovy in Action&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2006_rise_of_paul_king&quot;&gt;2006: Rise of Paul King&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 480 commits &lt;strong&gt;Community&lt;/strong&gt;: 480 commits (100%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Jochen Theodorou : 221 commits (46%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wilson : 56 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 54 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge : 47 commits (9%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dierk Koenig : 37 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeremy Rayner : 23 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 14 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Alleon : 12 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Joachim Baumann : 6 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin C. Martin : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Graeme Rocher : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Marc Guillemot : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Christian Stein : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Steve Goetze : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2006 is a very calm year for Groovy in terms of code production. James, the creator of the language, already disappeared from the contributors, and will not contribute anymore. &lt;strong&gt;Guillaume Laforge&lt;/strong&gt;, in agreement with the other contributors, &lt;strong&gt;takes the project lead&lt;/strong&gt; (he is still the lead today).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With half as many commits as in 2007, in retrospect, I would say that this was a critical year: either the project would die, or it would have become what it is today. And my personal feeling is that the person who saved Groovy just appeared in the contributors list: Paul King. &lt;strong&gt;Paul is undoubtfully the most active contributor to Groovy&lt;/strong&gt;. He wrote a lot of the Groovy Development Kit, that is to say the APIs without which a language would be nothing. Having a nice language is one thing, having proper APIs and libraries that unleash its full potential is another. Paul King did it. Look at his ranking here: 3rd place. You will never see him ranked lower than that. And guess what? Paul is &lt;strong&gt;not&lt;/strong&gt; paid to do this. He &lt;a href=&quot;https://www.asert.com.au/&quot;&gt;runs his own business&lt;/a&gt; and if you want to work with a Groovy expert, he&amp;#8217;s probably the best.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Joachim Baumann is a name some people would recognize: he is still working with Groovy and one of the most regular contributors, with the Windows installer. Joachim takes time, for each Groovy release, to produce a Windows installer, which today we are still not capable of handling automatically.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2007_groovy_1_0&quot;&gt;2007: Groovy 1.0&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Paul King : 447 commits (30%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jason Dillon : 265 commits (18%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 242 commits (16%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Danno Ferrin : 101 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alex Tkachman (Sponsored) : 87 commits (5%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Graeme Rocher (Sponsored) : 61 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 46 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Marc Guillemot : 36 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 34 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 33 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeremy Rayner : 26 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alexandru Popescu : 24 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wilson : 22 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Joachim Baumann : 21 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeff Brown : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dierk Koenig : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin C. Martin : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Alleon : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2007 is an important year in the history of Groovy. On 2nd January, Groovy 1.0 is out. &lt;strong&gt;Paul King ranks #1 for the first time, and will
remain on top for a long time&lt;/strong&gt;. This year also sees the creation of G2One, the first company build specifically for Groovy and Grails, by Guillaume
Laforge, Graeme Rocher and Alex Tkachman. Both Graeme and Alex make their first appearance in the contributors graph, and both of them made
significant contributions to the Groovy ecosystem: Graeme is famous for co-creating the Grails framework, and is still the lead of the project,
while Alex is the one who contributed major performance improvements to the Groovy runtime (call site caching) and first experimented with
a static compiler for Groovy (Groovy++).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Danno Ferrin contributed what is still one of my personal favorite features of Groovy, AST transformations, and probably one of the reasons
I got paid to work on Groovy so thank you Danno! Andrés Almiray,
listed here for the first time, is famous for the &lt;a href=&quot;https://griffon.codehaus.org/&quot;&gt;Griffon&lt;/a&gt; framework, a Grails-like framework for desktop applications which is still
actively developed. He spent a lot of time improving the Swing support in Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Starting from 2007, you will see that the &lt;em&gt;sponsored&lt;/em&gt; ratio of commits is changing. People who were employed by G2One fall into that category. As you
can see, 2007 is more than important for Groovy, it is its second birth. And to conclude that, Groovy won the first prize at JAX 2007 innovation award.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2008_the_g2one_era&quot;&gt;2008: The G2One era&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 1069 commits &lt;strong&gt;Sponsored&lt;/strong&gt;: 287 commits (26%) &lt;strong&gt;Community&lt;/strong&gt;: 782 commits (73%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Paul King : 445 commits (41%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Danno Ferrin : 176 commits (16%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 126 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alex Tkachman (Sponsored) : 125 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 33 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jim White : 32 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 31 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin Kempf : 22 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Roshan Dawrani : 19 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeremy Rayner : 14 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin C. Martin : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jason Dillon : 9 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thom Nichols : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Graeme Rocher (Sponsored) : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeff Brown : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wilson : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;James Williams : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Marc Guillemot : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vladimir Vivien : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In 2008, &lt;strong&gt;Paul King still ranks #1&lt;/strong&gt; and you can see that the people who were sponsored by G2One were actually not the main contributors. Actually, most
of them did consulting to pay salaries, which doesn&amp;#8217;t leave much time to contribute to the language. Hopefully, a great project such as Groovy can rely
on its community! Guillaume, Graeme and Alex were looking for an opportunity to spend more time on actual development, and it happened in November 2008
when G2One got acquired by SpringSource.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some of the contributors you see in this list are still actively using Groovy or contributing: Jim White for example is famous for his contributions on the scripting sides of the language. Roshan Dawrani is one of the few guys capable of opening cryptic code and fixing bugs. Jeff Brown is a name you should know, since he is now a key member of the Grails team.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2009_milestones_and_the_inappropriate_quote&quot;&gt;2009: milestones and the inappropriate quote&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 835 commits &lt;strong&gt;Sponsored&lt;/strong&gt;: 183 commits (21%) &lt;strong&gt;Community&lt;/strong&gt;: 652 commits (78%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Paul King : 342 commits (40%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Roshan Dawrani : 128 commits (15%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 101 commits (12%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alex Tkachman (Sponsored) : 41 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 40 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jason Dillon : 31 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jim White : 31 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Danno Ferrin : 24 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Niederwieser : 23 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hamlet D&amp;#8217;Arcy : 18 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 14 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin C. Martin : 13 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thom Nichols : 13 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vladimir Vivien : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Graeme Rocher (Sponsored) : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2009 is another important year concluding with the release of Groovy 1.7, the first version of Groovy supporting inner classes
or the famous power asserts from Peter Niederwieser. If you know Groovy, you must know Peter, the father of the famous Spock testing
framework which &lt;a href=&quot;https://groovy.329449.n5.nabble.com/Ann-Spock-1-0-has-been-released-td5722915.html&quot;&gt;just reached 1.0&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Hamlet D&amp;#8217;Arcy contributed a lot in terms of code quality&lt;/strong&gt;, but also became the first specialist of AST transformations. 2009 is also the year I started to use Groovy, as a user. I never stopped and actually I started contributing back
then. At that time, Groovy was still using Subversion (we&amp;#8217;re now using Git like all the cool kids), so it was the good old patch way,
loosing authorship.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This year is also the year when James Strachan wrote a very famous quote about Groovy. This quote is probably the most innapropriately
used quote about Groovy of all time, because it was done by its creator, but remember that James left the project in 2005!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
I can honestly say if someone had shown me the Programming in Scala book by Martin Odersky, Lex Spoon &amp;amp; Bill Venners back in 2003 I&amp;#8217;d probably have never created Groovy.
&lt;/blockquote&gt;
&lt;div class=&quot;attribution&quot;&gt;
&amp;#8212; James Strachan&lt;br&gt;
&lt;cite&gt;on his blog&lt;/cite&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all James says nothing about the language itself here. He had already left the project and says that &lt;strong&gt;if&lt;/strong&gt; he had known about Scala before, he &lt;strong&gt;wouldn&amp;#8217;t&lt;/strong&gt; have created Groovy. I am today very happy that he didn&amp;#8217;t know about it, or we would have missed an incredibly powerful language. Groovy today
is &lt;strong&gt;nothing close&lt;/strong&gt; to what it was when James left the project, thanks to the lead of Guillaume Laforge and incredibly talented people like Paul King, Jochen Theodorou and all the contributors listed on this page. Groovy and Scala both have their communities, but also different use cases. I wouldn&amp;#8217;t sell one for the other&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end of 2009, another important milestone occurred for project, with VMware acquiring SpringSource.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2010_dsls_all_the_way&quot;&gt;2010: DSLs all the way&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 894 commits &lt;strong&gt;Sponsored&lt;/strong&gt;: 189 commits (21%) &lt;strong&gt;Community&lt;/strong&gt;: 705 commits (78%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Paul King : 443 commits (49%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Roshan Dawrani : 134 commits (14%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 96 commits (10%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 93 commits (10%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hamlet D&amp;#8217;Arcy : 71 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alex Tkachman : 28 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Niederwieser : 19 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jason Dillon : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Russel Winder : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thom Nichols : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2010 is a pretty stable year for Groovy. Groovy reaches 1.8 in 2010 with important features for its incredible DSL design capabilities. With command chain expressions, native JSON support and performance improvements, Groovy put the bar very high in terms of integration in the Java ecosystem. Today, &lt;strong&gt;no other JVM language is as simple as Groovy to integrate with Java&lt;/strong&gt;. With cross-compilation and by the use of the very same class model, Groovy is at that date the best language for scripting on the JVM. It is so good that a lot of people start to see it as a better Java and want to use it as a first class language. However, being dynamic, Groovy is still a problem for a category of users&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2011_time_to_move_to_github&quot;&gt;2011: Time to move to GitHub&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 841 commits &lt;strong&gt;Sponsored&lt;/strong&gt;: 514 commits (61%) &lt;strong&gt;Community&lt;/strong&gt;: 327 commits (38%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Cédric Champeau (Sponsored) : 252 commits (29%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 212 commits (25%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 163 commits (19%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 98 commits (11%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen : 44 commits (5%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hamlet D&amp;#8217;Arcy : 33 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Roshan Dawrani : 26 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrew Eisenberg : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alex Tkachman : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bobby Warner : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Colin Harrington : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dierk Koenig : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dirk Weber : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wagenleitner : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lari Hotari (Sponsored) : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Niederwieser : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In 2011, I became a committer to the Groovy project. As I said, I had contributed several fixes or features for Groovy 1.8, but for the first time, I became a committer and I started to be able to push changes to the codebase without having to ask permission. So this is basically the first time you see my name on the contributors list, but you can see that I am ranking #1 and I have never lost that ranking since then. It surprised me too, but there is a very good reason for that. In october 2011, in addition to being a committer, I also became paid to work on Groovy. Full-time. &lt;strong&gt;I entered the club of lucky people being paid to work on open-source software&lt;/strong&gt;. It was sincerely a dream, and I will never be enough thankful to Guillaume Laforge for giving me this opportunity. He changed my life and I &lt;em&gt;think&lt;/em&gt; I became a better developer thanks to him. VMware was my employer back then, and while I had never worked on a language before, Guillaume trusted my skills and proposed to me to work on something that would dramatically change the language : a static type checker.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I also worked on the infrastructure of the language, starting from the migration to GitHub. It was an important move to make: as you can see, there was a very limited set of committers to Groovy. With &lt;a href=&quot;https://github.com/groovy/groovy-core/&quot;&gt;GitHub&lt;/a&gt;, we had the tool we needed to increase the size of our community and from the numbers that will follow, I think it&amp;#8217;s a success.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2012_groovy_2_and_static_compilation&quot;&gt;2012: Groovy 2 and static compilation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Cédric Champeau (Sponsored) : 515 commits (46%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 249 commits (22%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 169 commits (15%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 74 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PascalSchumacher : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Niederwieser : 11 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;René Scheibe : 11 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andre Steingress : 9 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wagenleitner : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Ledbrook : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adrian Nistor : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tim Yates : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Baruch Sadogursky : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrew Eisenberg : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rich Freedman : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stephane Maldini : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrew Taylor : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeff Brown : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luke Daley : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tiago Fernandez : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrey Bloschetsov : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Johnny Wey : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kenneth Kousen : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mathieu Bruyen : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul Bakker : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paulo Poiati : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sean Flanigan : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Suk-Hyun Cho : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vladimir Orany : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2012 is one of the most important years for the language. It was the year Groovy 2.0 was released. As you can see, I am still ranking #1 and Paul King, an unpaid contributor, is #2. This tells you the importance of community! Groovy 2 is a major change in the language, because it introduced both optional type checking and static compilation. For the first time, Groovy was able to provide at compile time the same level of feedback that Java would have. Some people wanted to kill me for having introduced that into the language. The truth is that it wasn&amp;#8217;t my decision, but in retrospect, I am very happy with what the language is now. Without this, some people would have abandonned Groovy in favor of other JVM languages like Scala, while now in Groovy you can have the same level of performance as Java, with type safety, powerful type inference, extension methods, functional style programming and without the boilerplate. And it&amp;#8217;s optional. I don&amp;#8217;t know any other language that allows this, especially when you take type checking extensions into account, a feature that allows Groovy to go far beyond what Java and other languages offer in terms of type safety or static compilation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2012 also sees the appearance of Pascal Schumacher, a silent but very active Groovy committer. Pascal does since 2012 an amazing job in helping us filtering JIRA issues, writing bugfixes, reviewing pull requests and lately writing documentation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2013_documentation_effort_and_explosion_of_contributions&quot;&gt;2013: Documentation effort and explosion of contributions&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Cédric Champeau (Sponsored) : 244 commits (22%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 188 commits (17%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PascalSchumacher : 180 commits (16%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 96 commits (8%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thibault Kruse : 84 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 54 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrey Bloschetsov : 43 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andre Steingress : 36 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pascal Schumacher : 27 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tim Yates : 24 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;René Scheibe : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;kruset : 12 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin Hauner : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Larry Jacobson : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wagenleitner : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paolo Di Tommaso : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeff Scott Brown (Sponsored) : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Masato Nagai : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Eddelbüttel : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hbaykuslar : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;shalecraig : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrew Eisenberg : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jacopo Cappellato : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Niederwieser : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rafael Luque : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vladimir Orany : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;saschaklein : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;seanjreilly : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;upcrob : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adrian Nistor : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alan Thompson : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Alessio Stalla : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DJBen : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Eric Dahl : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ingo Hoffmann : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JBaruch : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jacob Aae Mikkelsen : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jim White : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Engelman : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jon Schneider : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Karel Piwko : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kenneth Endfinger : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kohsuke Kawaguchi : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luke Kirby : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Michal Mally : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Miro Bezjak : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Olivier Croquette : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rob Upcraft : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sergey Egorov : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stefan Armbruster : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yasuharu NAKANO : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While continuing to improve Groovy, 2013 was very important for the community. You can start to see the GitHub effect here, with &lt;strong&gt;much&lt;/strong&gt; more contributors than before. It is impressive to see the difference before 2011 and after. The number of contributors is continously growing. In 2013, 63% of commits came from the community!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In February 2013, we also launched a new big project: the documentation and website overhaul. It is incredible to think that this effort is still uncomplete, but if you see that the old wiki has more than a thousand page or contents (often outdated), you can imagine what effort it takes to rewrite the documentation. Hopefully, we&amp;#8217;re close to filling the gap now, and with the demise of Codehaus, we officially launched our &lt;a href=&quot;https://groovy-lang.org&quot;&gt;new website&lt;/a&gt; where you can see the result of this job.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I also started working on Android support during 2013, for a first overview in GR8Conf 2014, and continued working on improving the infrastructure, with Bintray, TeamCity and Gradle. And Pivotal was born, out of EMC and VMware. Groovy and Grails, along with the Spring Framework, became part of this new company which is still paying me today to work on Groovy (and I, we, should be very thankful for this).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2014_towards_android_support&quot;&gt;2014: Towards Android support&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Cédric Champeau (Sponsored) : 446 commits (37%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 261 commits (22%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 85 commits (7%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Guillaume Laforge (Sponsored) : 61 commits (5%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thibault Kruse : 54 commits (4%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pascal Schumacher : 47 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jim White : 26 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yu Kobayashi : 18 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andre Steingress : 16 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Richard Hightower : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;James Northrop : 11 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kenneth Endfinger : 9 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tomek Janiszewski : 9 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Matias Bjarland : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tobia Conforto : 8 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Michael Schuenck : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sargis Harutyunyan : 7 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrey Bloschetsov : 6 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Craig Andrews : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kent : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paolo Di Tommaso : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Ledbrook : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sergey Egorov : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yasuharu Nakano : 5 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andrew Hamilton : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lari Hotari (Sponsored) : 4 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bloshchetsov Andrey Evgenyevich : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Johannes Link : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keegan Witt : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tim Yates : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;anto_belgin : 3 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Baruch Sadogursky : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dan Allen : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jan Sykora : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;John Wagenleitner : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luke Kirby : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Martin Stockhammer : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UEHARA Junji : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vihang D : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andres Almiray : 2 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andy Hamilton : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bobby Warner : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Carsten Lenz : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Chris Earle : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;David Avenante : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;David Nahodil : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;David Tiselius : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dimitar Dimitrov : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Grant McConnaughey : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jeff Sheets : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jess Sightler : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Logan Gorence : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luke Daley : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Manuel Prinz : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Marc Guillemot : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Marcin Grzejszczak : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nathan Mische : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Peter Swire : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sagar Sane : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stephen Mallette : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tobias Schulte : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Wil Selwood : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;davidmichaelkarr : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fintelia : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;kruset : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;paul-bjorkstrand : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2014 was a difficult year. We had a lot of work to do on the documentation side, new features to deliver (traits) and an important topic we definitely wanted to highlight: Android support. This took longer than expected, but in the end, the new &lt;a href=&quot;https://beta.groovy-lang.org/releasenotes/groovy-2.4.html&quot;&gt;Groovy 2.4&lt;/a&gt;. We&amp;#8217;re lucky to have half of the commits coming from the community here. Especially, lots of people helped us on the documentation. And it wasn&amp;#8217;t easy, because our documentation requires that every snippet of code that appears in the docs belongs to a unit test, to make sure that the documentation is always up-to-date.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Meanwhile, at the end of the year, we learnt from Pivotal that they would end sponsoring our jobs. It means that Guillaume Laforge, Jochen Theodorou and myself, for the Groovy team, plus Graeme Rocher, Jeff Brown and Lari Hotari, for the Grails team, were both loosing their jobs and full time to work on the project at the same time. This wasn&amp;#8217;t really a surprise and I am very happy I could work for so long on Groovy, full time, but as I said in a previous post I also wish I will still be able to do that, because you can see from the numbers and features that it matters. If you wonder, we are still discussing with several potential sponsors.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2015_your_story&quot;&gt;2015: Your story&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Total&lt;/strong&gt;: 178 commits &lt;strong&gt;Sponsored&lt;/strong&gt;: 81 commits (45%) &lt;strong&gt;Community&lt;/strong&gt;: 97 commits (54%)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Cédric Champeau (Sponsored) : 69 commits (38%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pascal Schumacher : 59 commits (33%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Jochen Theodorou (Sponsored) : 12 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Paul King : 12 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JBrownVisualSpection : 7 commits (3%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yu Kobayashi : 3 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Christoph Frick : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kamil Szymanski : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Michael Schuenck : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sean Gilligan : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sergey Egorov : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Thibault Kruse : 2 commits (1%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Andy Wilkinson : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maksym Stavytskyi : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mario Garcia : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Radovan Synek : 1 commits (0%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;2015 will be another important year. It&amp;#8217;s going to be huge for the community. Guillaume Laforge announced that he was joining Restlet, so for the first time since 2007 he will not be fully employed to work on Groovy, but I don&amp;#8217;t expect this to have a big impact on the language development itself: as you can see from the numbers, about half of the commits already come from the community and Guillaume didn&amp;#8217;t contribute much code lately. He was instead the lead of the project, the one that took decisions, the one speaking about the project and talking to and leading the community. He was the voice. It was a hard job, a very important one for Groovy. Guillaume is still today the lead of the project, and he will continue to contribute to the language, but I know from him that he wanted to be able to do more code, and put Groovy in action into a new project.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the &lt;a href=&quot;https://blog.pivotal.io/pivotal/news-2/groovy-2-4-and-grails-3-0-to-be-last-major-releases-under-pivotal-sponsorship&quot;&gt;end of sponsorship of Pivotal&lt;/a&gt;, the &lt;a href=&quot;https://www.codehaus.org/&quot;&gt;demise of Codehaus&lt;/a&gt; and &lt;a href=&quot;https://restlet.com/blog/2015/03/02/head-of-groovy-project-joins-restlet-to-lead-api-development-tools/&quot;&gt;Guillaume&amp;#8217;s decision&lt;/a&gt;, it became even more important to move Groovy to a foundation where it will be able to live with or without us. I have honestly no idea where I will work in a few weeks now. I sincerely hope I will still be able to contribute to the language full time, but let&amp;#8217;s be clear: today, it is very unlikely this is going to happen. It makes it very important for the project to be able to develop the community even more. We had more than 4.5 million downloads last year. This is huge. And with Android support, I see a lot of potential, even if we have tough competition with other languages and people being paid to develop them. The &lt;strong&gt;&lt;a href=&quot;https://apache.org&quot;&gt;Apache Software Foundation&lt;/a&gt; is going to help us with securing the future of the language and building a community&lt;/strong&gt;. I am proud of what you have done, collectively, and this is not over. Groovy is ready for a rebirth under the Apache umbrella!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;More than ever, the future of Groovy is you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To conclude this post, here are the top 10 contributors, in terms of number of commits, of Groovy, for the past 12 years. Congratulations Paul and thanks to our 100+ contributors!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;red&quot;&gt;Paul King :Paul King : 2653 commits (23%)&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Jochen Theodorou&lt;/strong&gt; : 1562 commits (13%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cédric Champeau&lt;/strong&gt; : 1526 commits (13%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;James Strachan&lt;/strong&gt; : 1031 commits (9%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Guillaume Laforge&lt;/strong&gt; : 709 commits (6%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Roshan Dawrani&lt;/strong&gt; : 307 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Jason Dillon&lt;/strong&gt; : 306 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Danno Ferrin&lt;/strong&gt; : 301 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alex Tkachman&lt;/strong&gt; : 283 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;John Wilson&lt;/strong&gt; : 230 commits (2%)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Looking for a new job</title>
      <link>https://melix.github.io/blog//2015/01/for-hire.html</link>
      <pubDate>Mon, 19 Jan 2015 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2015/01/for-hire.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_will_you_be_the_new_groovy_sponsor&quot;&gt;Will you be the new Groovy sponsor?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There we are. January 19th was a bad day as Pivotal &lt;a href=&quot;https://blog.pivotal.io/pivotal/news-2/groovy-2-4-and-grails-3-0-to-be-last-major-releases-under-pivotal-sponsorship&quot;&gt;announced that they wouldn&amp;#8217;t sponsor the development of the Groovy language&lt;/a&gt;, as well as its long time friend the Grails framework, starting from march 31st. As I was paid to work on Groovy, it has a direct consequence for me: starting from April 1st, I am &lt;strong&gt;for hire&lt;/strong&gt;. For you, it probably doesn&amp;#8217;t change much as Groovy and Grails existed before Pivotal without corporate funding.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was hard to keep this secret for weeks, but now that everything is public, it is easier for us. I have been lucky to work full time on the Groovy language for a bit more than 3 years now. Lucky because it was both a great open-source software and my passion. I have implemented major features of the language &lt;a href=&quot;https://github.com/groovy/groovy-core/graphs/contributors&quot;&gt;since Groovy 1.8&lt;/a&gt;: static type checking, static compilation, Android support, numerous AST transformations, continous integration&amp;#8230;&amp;#8203; I have given talks to various conferences, including world class ones like JavaOne, Devoxx, GR8Conf or SpringOne2GX and it was a fantastic opportunity that wouldn&amp;#8217;t have been possible without the support from VMware then Pivotal.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However I feel that &lt;strong&gt;I still have a lot to do&lt;/strong&gt;. So many things are on the list, so much to improve, like for example adding language support for asynchronous programming, improved Java 8 support, a new meta-object protocol, not forgetting, of course, bugfixes&amp;#8230;&amp;#8203; I am 100% convinced that the language wouldn&amp;#8217;t have reached the level of maturity it has without support from a company like Pivotal. And even though Java is considered mature, it doesn&amp;#8217;t mean that the language shouldn&amp;#8217;t continue to evolve: it is rather the opposite. People are constantly asking for evolutions, because programming models evolve too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For those reasons, my #1 choice would be to find a new company securing the development of Groovy and Grails, that is to say willing to pay me and my mates to continue working on them. The Groovy community is huge, there are lots of companies using Groovy in a variety of domains, I sincerely hope this is possible. With more than 4 million downloads in 2014, I can&amp;#8217;t imagine how many hours of development have been saved thanks to Groovy and Grails&amp;#8230;&amp;#8203; Should you be interested in sponsoring our projects, please write to &lt;a href=&quot;mailto:sponsorship@groovy-lang.org&quot;&gt;sponsorship@groovy-lang.org&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_about_me&quot;&gt;About me&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If unfortunately we can&amp;#8217;t find third parties willing to take over the development of the language and hire us, then I would obviously be available to help you in your projects. For those of you who are looking for someone with a good knowledge of the JVM internals, I am listening. My areas of interest:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;R&amp;amp;D&lt;/strong&gt;: innovation, technical challenges are what drive my motivation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;open-source&lt;/strong&gt; over closed-source: If you are an Open-Source company, by that I mean a company which contributes Open-Source, I think we are on the same line. I love to share what I do and I am convinced that open-source development is the best way to improve the global quality of a project. I have worked on closed-source software in the past, there are good reasons to do so but working on OSS software is really what I prefer. I also enjoy &lt;a href=&quot;https://speakerdeck.com/melix/&quot;&gt;speaking publicly&lt;/a&gt; about projects I work on.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;JVM&lt;/strong&gt;: I have spent most of my career on that platform and believe me, it&amp;#8217;s not dead :)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;back-end&lt;/strong&gt; over front-end: I love working on tooling, performance tuning, algorithmics&amp;#8230;&amp;#8203; everything that is hidden to the end user. On the other side I am not so good on the front-end part (HTML, CSS, &amp;#8230;&amp;#8203;) so it would probably not be a good idea to make me work on that topic :)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;remote working&lt;/strong&gt;: I live in Saint Hilaire de Loulay, a small countryside town near Nantes, in France. I have now been working from home for more that 3 years, most of the Spring Framework team works that way, and it has been very successful so far. If you are not against the idea, I would love to continue that way.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In any case if you think a profile like mine is interesting for your company, you can contact me or ask for my résumé at &lt;a href=&quot;mailto:cedric.champeau@gmail.com&quot;&gt;cedric.champeau@gmail.com&lt;/a&gt;. Meanwhile, rest assured that we are focused and we will soon release Groovy 2.4 to prove that!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>10 things your static language can&amp;#8217;t do</title>
      <link>https://melix.github.io/blog//2014/12/10-things-static-cant-do.html</link>
      <pubDate>Mon, 15 Dec 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/12/10-things-static-cant-do.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_but_maybe_mine_can&quot;&gt;But maybe mine can&amp;#8230;&amp;#8203;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For those of you who do not know me, and you are likely much more in that category than in the other, I&amp;#8217;ve been working on
the Groovy language full-time for more than 3 years now. I started as a user several years ago, in the context of DSLs,
and eventually became a contributor before getting employed to work on the language. I love static typing, but not at the
point of thinking that we should only reason about types. This is why I also love dynamic typing, and why I invested so
much in Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy is primarily a dynamic language. It is probably the most widely used alternative language on the JVM, with use cases ranging
from DSLs (scripting Jenkins builds for example) to full blown applications on mobile devices (Android), going through
full stack web applications with Grails. Despite being primarily a dynamic language, I spent a lot of time writing a
&lt;strong&gt;static compiler for Groovy&lt;/strong&gt;, making it a pretty unique language in the JVM world, but not limited to the JVM world:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy is a language which supports &lt;strong&gt;dynamic typing and compile-time type checking&lt;/strong&gt;. It makes it surprisingly powerful
and versatile language, capable of adapting to a great variety of contexts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I tell people that I wrote the static compiler for Groovy, I often get a reaction which is &quot;so you admit that dynamic
languages are less powerful than static ones&quot;, and they see me as the one that made the language &lt;strong&gt;right&lt;/strong&gt;. Oh no, I did not.
In fact, I love the dynamic aspects of the language. It is always annoying that I, as a designer of a static compiler, have
to defend dynamic languages, but it&amp;#8217;s an interesting topic, especially those days where I read lots of articles doing
dynamic-bashing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So in this post, I&amp;#8217;m going to illustrate 10 things that a static language (most likely) cannot do. It doesn&amp;#8217;t mean that there are only
10 things that a static language cannot do compared to a dynamic one, but it is here to illustrate the fact that this idea
that static languages are superior or more scalable just because they are &lt;em&gt;type safe&lt;/em&gt; is IMHO stupid. Compare languages between
them, but do not compare categories of languages. While static languages will be excellent in making type safety guarantees (errors
at compile time), dynamic languages are often far superior in cutting down verbosity. That&amp;#8217;s just an example which illustrates
that comparing on the sole aspect of type safety is not enough.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post I will also illustrate how Groovy is special, because it is capable of handling things in a &lt;strong&gt;mixed&lt;/strong&gt; mode, making it
totally unique and incredibly powerful, bringing the best of the two worlds together. Last disclaimer, this post is mostly centered on
the JVM world, because this is the one I know the best.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock caution&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-caution&quot; title=&quot;Caution&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
As expected I got lots of comments on various social media. Some are positive, some not, that&amp;#8217;s ok, but again, I
would like to remember that this is &lt;strong&gt;not&lt;/strong&gt; static languages bashing, nor dynamic languages promotion. Maybe some of you
will think &quot;hey, but my static language can do it!&quot; and yes, it is possible, because as the subtitle of this post says,
mine can too. But when it does, often, there&amp;#8217;s a drawback (like loosing type safety, decreased performance,&amp;#8230;&amp;#8203; ) or you fall on
dynamic behavior without even noticing it. When it is the case, I tried to be honest and tell about the possibilities. But I also
voluntarily hide some static features of Groovy that make it a very interesting solution (flow typing for example). Last but not
least, I am not saying that &lt;strong&gt;all&lt;/strong&gt; dynamic features implement &lt;strong&gt;all&lt;/strong&gt; those items. I am saying that by nature a dynamic language make
it possible. An possible doesn&amp;#8217;t mean required. So please read carefully before screaming!
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ready?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_10_object_oriented_programming_done_right&quot;&gt;10. Object-oriented programming done right&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is a very academic point of view. Users of static languages tend to think that their language is object-oriented. Because C++
has a compiler, because Java has a compiler, means that statically typed languages have to be compiled. Object oriented programming
does &lt;strong&gt;not&lt;/strong&gt; require languages to be compiled. OOP is about &lt;strong&gt;message passing&lt;/strong&gt;. Object-oriented programming does &lt;strong&gt;not&lt;/strong&gt; imply type safety.
It means that an object is something that receives messages. In the Java world, the message is a method with arguments, and the contract
is enforced at compile time, but it is an implementation detail which reduces OO programming to a small subset of its capabilities.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The great Alan Kay himself &lt;a href=&quot;https://lists.squeakfoundation.org/pipermail/squeak-dev/1998-October/017019.html&quot;&gt;explains it&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy, as a dynamic language, supports commons OOP concepts (and also functional concepts) like class, interface, abstract classes or traits
but also has a meta-object protocol. For those of you who did Smalltalk programming, it&amp;#8217;s the same idea: the behavior of objects is not determined at compile time, it&amp;#8217;s a runtime behavior determined by a meta-object protocol. In Groovy, it translates to the fact that to each class corresponds
a meta-class which determines the behavior that an object will have when it receives a message (a method call).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This capability of doing things at runtime instead of compile time is the core of many features of dynamic languages and most of the
points illustrated in this blog post derive from it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-note&quot; title=&quot;Note&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
I had some comments that the fact that dynamic languages can do OO right wasn&amp;#8217;t really interesting. In fact, I insisted on keeping this
because this is actually what makes most of the following items possible. So think of 10. as the basement for most of the following items.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_9_multimethods&quot;&gt;9. Multimethods&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Java supports overloaded methods. The question whether it is a good or a bad idea is beyond the scope of this post (and believe me
it is a very interesting question both in terms of semantics and performance). The idea is that an object can have two methods
of the same name accepting different parameters. Let&amp;#8217;s illustrate this with Java code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static int foo(String o) { return 1; }
public static int foo(Date o) { return 2; }
public static int foo(Object o) { return 3; }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you call it like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static void main(String[] args) {
    Object[] array = new Object[] { &quot;a string&quot;, new Date(), 666 };
    for (Object o : array) {
        System.out.println(foo(o));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What do you think it prints? Well, most beginners will probably answer something that looks natural when you know the contents of the array:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;1
2
3&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But the correct answer is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;3
3
3&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Because the static type of &lt;code&gt;o&lt;/code&gt; when the call to &lt;code&gt;foo&lt;/code&gt; is made is &lt;code&gt;Object&lt;/code&gt;. To say it more clearly, the declared type of &lt;code&gt;o&lt;/code&gt; is &lt;code&gt;Object&lt;/code&gt; so we are calling &lt;code&gt;foo(Object)&lt;/code&gt;. The reason for this is that the code is &lt;strong&gt;statically compiled&lt;/strong&gt; so the compiler has to know at compile time which method is going to be called. A dynamic language like Groovy chooses the method at runtime (unless, of course, you use &lt;code&gt;@CompileStatic&lt;/code&gt; to enforce static semantics), so the method which is going to be called corresponds to the &lt;strong&gt;best fitting arguments&lt;/strong&gt;. So Groovy, unlike Java, will print the less surprising result:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;1
2
3&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It is theorically possible for a static language to do the same. But it comes at the price of performance. It would mean that the arguments have to be checked at runtime, and since static languages do not, as far as I know, implement an inlining cache, performance would be lower than those of a well designed dynamic language&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But to add something to a dynamic language, what if you remove the &lt;code&gt;Object&lt;/code&gt; version of &lt;code&gt;foo&lt;/code&gt;, and remove &lt;code&gt;666&lt;/code&gt; from the array? As an exercise to the reader, would this Java code compile?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static int foo(String o) { return 1; }
public static int foo(Date o) { return 2; }

public static void main(String[] args) {
    Object[] array = new Object[] { &quot;a string&quot;, new Date() };
    for (Object o : array) {
        System.out.println(foo(o));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If not, what do you have to do to make it pass? Yes, dynamic languages are superior here&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_8_duck_typing&quot;&gt;8. Duck typing&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Duck typing has always been a selling point of dynamic languages. Basically imagine two classes:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class Duck {
   String getName() { &apos;Duck&apos; }
}
class Cat {
   String getName() { &apos;Cat&apos; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those two classes define the same &lt;code&gt;getName&lt;/code&gt; method, but it is not defined explicitly in a contract (for example through an interface). There are many reasons why this can happen. For example, you didn&amp;#8217;t write those classes, they are in a third party library and for some reason those methods were not intended to be part of the contract. Imagine that you have a list of objects containing either ducks, cats, or anything else definining a &lt;code&gt;getName&lt;/code&gt; method. Then a dynamic language will let you call that method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def list = [cat, dog, human, hal]
list.each { obj -&amp;gt;
   println obj.getName()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A static language like Java would force you to have a cast here. But since you don&amp;#8217;t have an interface defining &lt;code&gt;getName&lt;/code&gt; and implemented by all objects, you cannot cast to that type so you have to consider all types and delegate appropriately like in the following code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;if (obj instanceof Cat) {
   return ((Cat)obj).getName();
}
if (obj instanceof Duck) {
   return ((Duck)obj).getName();
}
if (obj instanceof Human) {
   return ((Human)obj).getName();
}
if (obj instanceof Computer) {
   return ((Computer)obj).getName();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The real solution in Java is to define either a common super class or an interface for all those, but again, sometimes you just cannot because you don&amp;#8217;t have access to the code! Imagine that the &lt;code&gt;Cat&lt;/code&gt; and &lt;code&gt;Dog&lt;/code&gt; classes where designed like this for example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public abstract class Something {} // should define getName, but does not for some obscure reason
public class Cat extends Something {
   public String getName() { return &quot;Cat&quot;; }
}
public class Dog extends Something {
   public String getName() { return &quot;Dog&quot;; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Often the developer didn&amp;#8217;t even realize that all objects share a common interface. That&amp;#8217;s bad for you, and if you find this code you have no choice but the cascading &lt;em&gt;instanceof&lt;/em&gt; solution. There are multiple issues with that code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it is very repetitive, the only thing which changes is the type used in the test and the cast&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it has to be extensive, that is to say that if your list happens to contain an object having a &lt;code&gt;getName&lt;/code&gt; method but not in your list of cases to consider, the code is broken. This means that you have to think about changing that method if you add a new type in your list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;in the JVM world, as the number of cases to consider grows, the size of the method will increase to the point where the JIT (just-in-time compiler) decides it&amp;#8217;s not worth inlining, potentially dramatically reducing performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, one may say &quot;but why the hell didn&amp;#8217;t you use an interface&quot;. This is of course a good way to solve this in Java, but it is not always possible. Not for example if you don&amp;#8217;t have access to the source code (think of the various classes being split in third party libraries). I often faced this problem in the past, and believe me it&amp;#8217;s no fun (I look at you, &lt;em&gt;Apache Lucene&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are actually alternatives for static languages. In Java, you could use a reflective proxy: define an interface, then create a proxy implementing that interface which will delegate to the appropriate &lt;code&gt;getName&lt;/code&gt; method. Of course it is overkill: for each object of your list you have a proxy instantiated&amp;#8230;&amp;#8203; Another option, again in Java, is to make the call reflective. But in that case, the call becomes slow and in fact, what you are doing is a dynamic call like a dynamic language would do. A language like Groovy doesn&amp;#8217;t have that problem because it implements smart techniques like call site caching and runtime bytecode generation which make it much faster than what a reflective call would do&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;An elegant alternative used by other static languages is &lt;strong&gt;structural typing&lt;/strong&gt;. This is for example what the &lt;code&gt;Go&lt;/code&gt; language does. In this case, you define an interface, but the object does not have to explicitly implement the interface: the fact that the object defines a method corresponding to the method in the interface is enough to implement it. This is elegant but it changes the semantics of an interface as you define it in Java. Last but not least, this technique cannot be used on a platform like the JVM, because the virtual machine has no way to do it. Well, this is not totally true since now we have the &lt;em&gt;invokedynamic&lt;/em&gt; bytecode instruction but guess what? You are relying on a &lt;em&gt;dynamic&lt;/em&gt; feature of the VM&amp;#8230;&amp;#8203; Can you hear it?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock note&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-note&quot; title=&quot;Note&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Some argued that this is very bad design. I must repeat that if you think so, you missed the point. The idea is to &lt;strong&gt;workaround poorly designed
APIs&lt;/strong&gt; (or APIs which were &quot;optimized&quot;). When I talked about &lt;em&gt;Lucene&lt;/em&gt; it was for a very good reason. I faced the problem. &lt;em&gt;Lucene&lt;/em&gt; is a highly
optimized piece of code. It makes design decisions which are often based on performance: flattening as much as possible class hierarchies (the HotSpot
JIT doesn&amp;#8217;t like deep class hierarchies), make classes final, prefer abstract classes over interfaces, &amp;#8230;&amp;#8203; So it is easy to find classes that you want
to extend, but you can&amp;#8217;t because they are final, or classes that implicitly implement a contract but do not define interfaces. This is a pain to work
with, and the ability of a dynamic language to be able to call such methods without having to explicitly declare a contract is a real gain. Some
static languages offer similar features through structural typing, but then you have to think about what it means (virtual table lookup?) and how
it is implemented depending on the platform (on the JVM, relying on reflection is possible but you loose all type safety and have very bad performance). So everytime I used duck typing, it wasn&amp;#8217;t on APIs that &lt;strong&gt;I&lt;/strong&gt; had designed. It was on 3rd party APIs, that for some reason didn&amp;#8217;t provide
me with a way to call some methods.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_7_respond_to_non_existing_methods&quot;&gt;7. Respond to non-existing methods&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A dynamic language answers to messages (method calls) at runtime. This means that a well designed dynamic language should be able to let you answer &lt;strong&gt;any&lt;/strong&gt; kind of method call, including&amp;#8230;&amp;#8203; non existing methods! This feature is at the core of powerful facilitating frameworks like Grails. In Grails, you can define a domain class like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class Person {
   String firstName
   String lastName
   int age
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;Person&lt;/code&gt; class does not define any method, nor does it have any explicit relation to a datastore, an ORM or SQL server. However, you can write code like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def adults = Person.findByAge { it&amp;gt;= 18 }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I will not dig into the details about how this is done, but the idea is to intercept the fact that the &lt;code&gt;findByAge&lt;/code&gt; method does not exist, then parse the name of the method and build a query based on the method name and the rest of the arguments (here, a closure, an open block of code). Queries can be as complex as you wish, like &lt;code&gt;findByLastNameAndAge&lt;/code&gt; or whatever you can think of. Of course Grails does some smart things here, like &lt;strong&gt;generating a new method at runtime&lt;/strong&gt;, so that the next time this method is hit, it is not an unknown method anymore, and can be invoked faster! Only a dynamic language would let you do that. Say bye to infamous DAOs that you have to change everytime you have
a new query, it is not necessary. One could say that they prefer safety at compile time rather than the ability to do this, but Grails also offers that possibility of checking that the syntax is correct at compile time, while still leveraging the dynamic runtime to make this work&amp;#8230;&amp;#8203; It&amp;#8217;s all about boilerplate removed, code verbosity and productivity&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The ability to react to arbitrary messages is actually at the core of many DSLs (domain specific languages) written in Groovy. They are at the core of builders for example, which will let you write code like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;catalog {
   book {
   	isbn 123
	name &apos;Awesome dynamic languages&apos;
        price 11.5
        tags {
	   dynamic,
	   groovy,
	   awesome
	}
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Instead of the less readable Java 8 version (for the reader&amp;#8217;s mental sanity, I will not write the Java 7 version):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;builder.catalog( (el) -&amp;gt; {
  el.book ( (p) -&amp;gt; {
     p.setISBN(&quot;123&quot;);
     p.setName(&quot;Awesome dynamic languages&quot;);
     p.setPrice(11.5);
     p.setTags(&quot;dynamic&quot;,&quot;groovy&quot;,&quot;awesome&quot;);
  })
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_6_mocking_and_monkey_patching&quot;&gt;6. Mocking and monkey-patching&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Mocking is at the core of many unit testing strategies. Most of static languages make use of an external library to do this. Why this can be true of dynamic languages too, this is often not strictly necessary. For example Groovy offers built-in stubbing/mocking capabilities, very easily thanks to its dynamic nature. Monkey patching rely on the very same behavior but is easier to explain so I will illustrate this concept here. Imagine that you use a closed-source library (I won&amp;#8217;t judge you, I promise) or an open-source library for which you don&amp;#8217;t want to/don&amp;#8217;t have time to contribute to, but you have found a serious security issue in a method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class VulnerableService {
   public void vulnerableMethod() {
      FileUtils.recurseDeleteWithRootPrivileges(&quot;/&quot;);
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You know how to fix it, but you have to wait for the maintainer to upgrade the library. Unfortunately, you can&amp;#8217;t wait because attackers are already leveraging the vulnerability on your production server (yeah, they like to). One option that a dynamic language can let you do is redefine the method at runtime. For example, in Groovy, you could write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;VulnerableService.metaClass.vulnerableMethod = {
   println &quot;Well tried, but you have been logged to Santa&apos;s naughty guys list!&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then a caller that would call the vulnerableMethod would call the monkey-patched version instead of the original one. Of course in a language like Groovy, this would only be true if the callee is dynamically compiled: if you use &lt;code&gt;@CompileStatic&lt;/code&gt; to behave like a static compiler, you&amp;#8217;re out of luck, because the method which will be invoked is selected at compile time, so you &lt;strong&gt;will&lt;/strong&gt; be vulnerable even if you try to monkey patch&amp;#8230;&amp;#8203; Groovy provides other extension mechanisms to work around this, but it&amp;#8217;s not the topic here ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_5_dynamic_objects&quot;&gt;5. Dynamic objects&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Most dynamic languages let you create&amp;#8230;&amp;#8203; dynamic objects. It is basically an object for which you attach methods and properties &lt;em&gt;at runtime&lt;/em&gt;. Not that I am a big fan of it but there are some valid use cases (serialization, languages like &lt;a href=&quot;https://github.com/golo-lang/golo-lang/&quot;&gt;Golo&lt;/a&gt; not supporting classes, prototype based construction, &amp;#8230;&amp;#8203;). It can also be convenient if you want to rapidly prototype a class.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an example, let&amp;#8217;s see how you could create an arbitrary object to represent a person, without actually leveraging on a class, using the Groovy language:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def p = new Expando()
p.name = &apos;Cédric&apos;
p.sayHello = { println &quot;Hello $name&quot; }

p.sayHello()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code is totally dynamic here. It lets you create an arbitrary object, attach new methods to it, data, &amp;#8230;&amp;#8203;, without relying on strong typing. Of course it is interesting when you see that the &lt;code&gt;sayHello&lt;/code&gt; method is capable of referencing &quot;pseudo-fields&quot; which are themselves dynamic!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_4_scripting&quot;&gt;4. Scripting&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Static languages can do scripting. But it is definitely not what I would call scripting. Having to write types is not natural in a script. I even worked in the past in a context where people who wrote scripts where not programmers. They didn&amp;#8217;t even know what a type is, and they don&amp;#8217;t care. The most popular scripting technologies like Bash do not have types, and it&amp;#8217;s not a problem, so imagine the following. You arrive late at your office, your boss is very angry about that and shouts to you: &quot;you have 5 minutes, not more, to give me the total number of followers of users who have submitted an accepted pull request on the Groovy repo recently&quot;. It&amp;#8217;s a weird query, most probably your boss is going into social networking madness but you have no choice otherwise you&amp;#8217;re fired.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In that case, most developers would think of:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;using a Bash script combining &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, regular expressions and hoping that &lt;code&gt;man&lt;/code&gt; works&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;using a tool they know like Java, but since they have so little time, they will probably rely on a regular expression to parse the JSON feed until they realize they have to do a second HTTP query for each user&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;quiting their job&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Groovy, you would do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.json.JsonSlurper

def json = new JsonSlurper().parse(&apos;https://api.github.com/repos/groovy/groovy-core/issues?state=closed&apos;.toURL())
json.user.collectEntries { u -&amp;gt;
   // second query to fetch the nb of followers
   def followers = new JsonSlurper().parse(u.followers_url.toURL())
   [u.login,followers.size()]
}.values().sum()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What you can see here is that we use a facility, &lt;code&gt;JSonSlurper&lt;/code&gt; which actually parses the JSON result. It is much more reliable that what you would have done with a quick hack like a regex, but not only:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;all data is accessible in a path-like fashion (&lt;code&gt;json.user.address.city.postalCode&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you don&amp;#8217;t need a single type here&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even if you use a smart JSON parser with your static language, you would still have to write a collection of classes to unmarshall the JSON structure into beans/classes. For such a simple use case, you really don&amp;#8217;t care. You just want things done, easily, quickly. You don&amp;#8217;t need type safety. You don&amp;#8217;t need it to be super clean and tolerant to future changes of the JSON format. Get. Things. Done. (and boss happy).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_3_runtime_coercions&quot;&gt;3. Runtime coercions&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another thing that dynamic languages are particularily good at is runtime coercions. In general static languages users know about one type of conversion, which is casting. Some are lucky enough to know about coercion (like the use of &lt;em&gt;implicit&lt;/em&gt; in &lt;em&gt;Scala&lt;/em&gt;), the others rely on the adapter pattern. In a dynamic language, runtime coercions are often easy to implement. A coercion differs from a cast in the sense that you want to convert an object of &lt;code&gt;class A&lt;/code&gt; to an object of &lt;code&gt;class B&lt;/code&gt;, but a &lt;code&gt;B&lt;/code&gt; cannot be assigned to an &lt;code&gt;A&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy provides &quot;natural&quot; conversions for some widely used types: lists to objects, and maps to object, like in the example here:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;Point p = [1,2] // coercion of a list literal into an object of class Point thanks to constructor injection
Point p = [x:1, y:2] // coercion of a map literal into an object of class Point thanks to setter injection&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But if it happened to be that you cannot use maps or lists but really want to convert one type to another, you can just declare a converter:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class A {
   Object asType(Class&amp;lt;?&amp;gt; clazz) { new B(...) }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I can see you raising an eyebrow here, because I wrote the conversion code directly in class &lt;code&gt;A&lt;/code&gt;, but remember it&amp;#8217;s a dynamic language with a meta-object protocol, so nothing prevents you from writing this conversion code &lt;strong&gt;outside&lt;/strong&gt; of the class &lt;code&gt;A&lt;/code&gt; itself, through its metaclass, which would let you add conversion algorithms for classes which are beyond your control. It&amp;#8217;s a win!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_2_dynamic_binding&quot;&gt;2. Dynamic binding&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dynamic binding is linked to DSL evaluation and scripting. Imagine the following script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;a+b&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this script, variables &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; are &lt;code&gt;unbound&lt;/code&gt;. They are not known from a compiler, so if you tried to statically compile this with a compiler like &lt;em&gt;Java&lt;/em&gt; (or &lt;em&gt;C++&lt;/em&gt;, or &lt;em&gt;Scala&lt;/em&gt;) it would definitely blow up. Not if you compile this with &lt;em&gt;Groovy&lt;/em&gt;. Because it&amp;#8217;s dynamic, it&amp;#8217;s able to know that those variables &lt;strong&gt;will&lt;/strong&gt; be eventually bound, when the script is executed. Groovy provides means to &lt;em&gt;inject&lt;/em&gt; those variables when you need them. It is some kind of late binding, but it is the core of expression languages, and it is no surprise that products like &lt;a href=&quot;https://www.elasticsearch.org/guide/en/elasticsearch/reference/1.4/modules-scripting.html#modules-scripting&quot;&gt;ElasticSearch&lt;/a&gt; uses &lt;a href=&quot;https://www.elasticsearch.org/guide/en/elasticsearch/reference/1.4/modules-scripting.html#modules-scripting&quot;&gt;Groovy as the default scripting language&lt;/a&gt;: it allows it to be both compilable and late bound. But there is more, if you think you have an issue with not being able to resolve &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; at compile time and that you fear to write code which might fail at runtime&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_1_mixed_mode_compilation&quot;&gt;1. Mixed mode compilation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last thing that a dynamic language like Groovy is capable of doing is leveraging &lt;strong&gt;mixed mode&lt;/strong&gt; compilation. Behind this curious term is a unique concept in programming languages: Groovy is able of mixing static code with dynamic code, but more, you can instruct the compiler how to do so. So if you design a DSL like in &lt;a href=&quot;https://www.elasticsearch.org/guide/en/elasticsearch/reference/1.4/modules-scripting.html#modules-scripting&quot;&gt;ElasticSearch&lt;/a&gt; where you know that some variables will be bound, that the number, names and &lt;strong&gt;types&lt;/strong&gt; of those variables are fixed and known in advance, then you can instruct the compiler and switch to a statically compilable mode! This means that if the user uses an unknown variable, compilation will fail.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This technique is already used in Groovy itself, in the powerful &lt;a href=&quot;https://docs.groovy-lang.org/latest/html/documentation/markup-template-engine.html&quot;&gt;Markup Template Engine&lt;/a&gt;. It is a template engine which is capable of generating markup-like contents with a very nice builder-like syntax, but all templates are statically compiled even if the code seems to be full of unresolved method calls or variables!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For those who are interested in this, I invite them to take an eye at my &lt;a href=&quot;https://melix.github.io/blog/2014/02/markuptemplateengine.html&quot;&gt;blog posts&lt;/a&gt; describing how you can do this.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h1 id=&quot;_conclusion&quot; class=&quot;sect0&quot;&gt;Conclusion&lt;/h1&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In conclusion, I have highlighted some points where dynamic languages can do what static languages cannot. Users of the most widely used dynamic language, Javascript, probably have lots of ideas too. The point for me is &lt;strong&gt;not to tell which one is better than the other&lt;/strong&gt; because &lt;strong&gt;I don&amp;#8217;t care&lt;/strong&gt;. In general, I am not much into the war behind those, because I really enjoy both. I do static typing most of time, but I really enjoy the dynamic nature of the language too because often I don&amp;#8217;t want to be slowed down just to make a compiler happy. I, as a developer, should be happy. Making a compiler happy is secondary and often not necessary. Last but not least, you might have thought, reading this post, that &lt;strong&gt;your&lt;/strong&gt; static language can do this or that. I won&amp;#8217;t blame you here, because mine can too. The idea here is more to show that it is totally unnatural for a static language or it often comes with horrible drawbacks like verbosity, performance issues or simply difficult to implement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So what about using a &lt;a href=&quot;https://beta.groovy-lang.org&quot;&gt;language that brings the best of the two worlds together&lt;/a&gt;?&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Fixing Bluetooth debugging on Android Wear</title>
      <link>https://melix.github.io/blog//2014/10/android-moto360.html</link>
      <pubDate>Mon, 20 Oct 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/10/android-moto360.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have been working on making &lt;a href=&quot;https://beta.groovy-lang.org&quot;&gt;Groovy&lt;/a&gt; work on Android for several months now. In the last weeks, I even
showed at SpringOne2GX an example of an application written in Groovy that worked on Android Wear. However, that code
worked in an emulator. Recently, I got a real device, a Moto 360, so I wanted to see that application running on a
real device. For some very obscure (understand buggy Android SDK) reason, it was far from being that easy&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I litteraly spent &lt;strong&gt;hours&lt;/strong&gt; trying to figure out what was wrong, so I thought it would be interesting for those of you
who face the same problem to have a blog post that explains how to deal with it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_problem&quot;&gt;The problem&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you follow the instructions on the &lt;a href=&quot;https://developer.android.com/training/wearables/apps/bt-debugging.html&quot;&gt;Android documentation&lt;/a&gt;
about how to enable bluetooth debugging, it&amp;#8217;s in the end pretty simple. Basically, it&amp;#8217;s about enabling USB debugging on your physical
handheld, then enable bluetooth debugging on your wearable, and in the end enable bluetooth debugging in the Android Wear companion app.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The guide says:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;quoteblock&quot;&gt;
&lt;blockquote&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the Android Wear companion app, you should see the status change to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Host: connected
Target: connected&lt;/p&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, whatever I did, the &lt;code&gt;Target: connected&lt;/code&gt; line never appeared for me. It was &lt;strong&gt;always&lt;/strong&gt; &lt;code&gt;Target: disconnected&lt;/code&gt;, so if I continued
with the instructions:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;adb forward tcp:4444 localabstract:/adb-hub; adb connect localhost:4444&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Doing&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;adb devices&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Only showed my wearable as &lt;code&gt;offline&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;List of devices attached

dcfbbafd	device
localhost:4444	offline&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/rage-offline.jpg&quot; alt=&quot;Why so evil?&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have searched for an answer in a lot of pages, including &lt;a href=&quot;https://stackoverflow.com/questions/25938998/debugging-on-moto-360&quot;&gt;Stackoverflow&lt;/a&gt; where
I tried very unlikely answers like in &lt;a href=&quot;https://stackoverflow.com/questions/25938998/debugging-on-moto-360&quot;&gt;this page&lt;/a&gt;: execute both commands separately instead
of doing them in the same line. I thought that maybe there was a timing issue and that the fact of separating both commands would give the toolkit a chance,
but no, wasn&amp;#8217;t that easy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, I was totally convinced that the problem was because I had previously associated my handheld with an emulator. I was convinced of it because even if I had now associated it with a real device (the Moto 360), in the Android Wear companion app, the device was recognized as an &quot;emulator&quot;&amp;#8230;&amp;#8203; mmm&amp;#8230;&amp;#8203; So I tried uninstalling the Android Wear app, clear its cache, but no matter what I did, after reinstalling, the settings were kept, and the Moto recognized as an emulator. So sad&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_solution&quot;&gt;The solution&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So you were looking at a solution, and here it is. Basically, the problem is that the Android companion app doesn&amp;#8217;t store its settings under its cache. They are stored in the &lt;code&gt;Google Play Services&lt;/code&gt; space, so here is the procedure that worked for me, and I sincerely hope it will do for you. On your handheld:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;open the applications settings, search for the &lt;code&gt;Android Wear&lt;/code&gt; application, then &lt;strong&gt;force stop it&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;clear its &lt;strong&gt;data and cache&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;now search for &lt;code&gt;Google Play Services&lt;/code&gt; (depending on your language settings, it can appear with a different name, on m y device it is &quot;Services Google Play&quot;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;click on &lt;code&gt;Manage space&lt;/code&gt;. You will see that there&amp;#8217;s a section for connected devices. I tried to clear data here, but it didn&amp;#8217;t help, so you have to click on &lt;strong&gt;delete all data&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reboot your phone&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reboot your Moto 360&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am unsure that the two last steps are really necessary, but I did it because I wanted to make sure that force stopping and clearing data did not introduce some weird behavior after that. When you reopen the Android Wear companion app, it should now be as if it was the first time you opened it and ask you to associate it with your watch. Do it, and now, you should be able to follow the normal procedure described in the Android documentation and&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/yes-baby.jpg&quot; alt=&quot;yes baby&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Success, now you can debug your application on a real device (which includes deploying it&amp;#8230;&amp;#8203;).&lt;/p&gt;
&lt;/div&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;fr&quot;&gt;&lt;p&gt;Hey, finally got it working! I need to blog about how I arrived the insane emulator issue... &lt;a href=&quot;https://twitter.com/hashtag/groovylang?src=hash&quot;&gt;#groovylang&lt;/a&gt; &lt;a href=&quot;https://t.co/XINccF3V7k&quot;&gt;pic.twitter.com/XINccF3V7k&lt;/a&gt;&lt;/p&gt;&amp;mdash; Cédric Champeau (@CedricChampeau) &lt;a href=&quot;https://twitter.com/CedricChampeau/status/523934124898521090&quot;&gt;19 Octobre 2014&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Tip of the day: reversed git bisect</title>
      <link>https://melix.github.io/blog//2014/07/bisecting-groovy.html</link>
      <pubDate>Wed, 23 Jul 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/07/bisecting-groovy.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had an interesting use case for &lt;code&gt;git bisect&lt;/code&gt; today and as my blog also consistutes a good archive for things I don&amp;#8217;t
want to loose, let&amp;#8217;s take advantage of this to share the trick with you!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Normally, &lt;code&gt;git bisect&lt;/code&gt; is used to find what commit introduced a regression in the codebase. For example, if you know
that current &lt;code&gt;HEAD&lt;/code&gt; is buggy but that at least, RELEASE_1_0 was good, then you can write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git bisect start             &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
git bisect bad               &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
git bisect good RELEASE_1_0  &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;start bisecting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;tells that &lt;code&gt;HEAD&lt;/code&gt; contains the regression&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;tells that &lt;code&gt;RELEASE_1_0&lt;/code&gt; is a tag corresponding to a version known not to have the bug&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Git will checkout a revision that you can test, and you issue a list of &lt;code&gt;git bisect good&lt;/code&gt; or &lt;code&gt;git bisect bad&lt;/code&gt; commands
until it determines what commit introduced the regression.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is a &lt;strong&gt;very&lt;/strong&gt; practical way to find a regression. In Groovy, I&amp;#8217;ve used this more than once, it&amp;#8217;s very useful.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_reversing_the_logic&quot;&gt;Reversing the logic&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But today, I wanted to &lt;em&gt;reverse the logic&lt;/em&gt;. Actually, we had a &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY-6463&quot;&gt;bug report&lt;/a&gt;
and we found out that the bug was already fixed, but we didn&amp;#8217;t know in which version it was fixed. So actually, I didn&amp;#8217;t
want to find a regression, but a fix commit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea to do this is to reverse the meaning of &lt;code&gt;bad&lt;/code&gt; and &lt;code&gt;good&lt;/code&gt; in &lt;code&gt;bisect&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;bad&lt;/code&gt; becomes &quot;doesn&amp;#8217;t produce a compile error&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;good&lt;/code&gt; becomes &quot;produces a compile error&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And since the range of revisions to test was pretty big (we know that the error was reported on Groovy 2.2.1, but master
is 2.4.0), then I also took advantage of the &lt;code&gt;git bisect run&lt;/code&gt; command, which automatically continues bisecting based on
a command line return status code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So basically, here&amp;#8217;s what I wrote:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git bisect start                &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
git bisect bad master           &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
git bisect good GROOVY_2_2_1    &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
git bisect run ./bisect.sh      &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;start bisecting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;master is known to have the fix, so we say &lt;strong&gt;bad&lt;/strong&gt; is master&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;GROOVY_2_2_1 is known to have the bug, so we say &lt;strong&gt;good&lt;/strong&gt; is GROOVY_2_2_1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;start automatic bisecting thanks to the ./bisect.sh script&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And what does &lt;em&gt;bisect.sh&lt;/em&gt; consist of? Here you go:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;bisect.sh&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;#!/bin/bash
export GROOVY_HOME=/tmp/testversion                                                                     &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
./gradlew clean -x javadoc -x groovydoc -x javadocAll -x groovydocAll -PskipIndy=true installGroovy     &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
/tmp/testversion/bin/groovy bisect.groovy || exit 0                                                     &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
exit 1                                                                                                  &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;tells where the local build version of Groovy will be installed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;builds Groovy and installs it locally&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;executes the test script and if the test fails, return a success exit code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;return a failure exit code&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The trick is to &lt;strong&gt;reverse the exit codes&lt;/strong&gt; in the script too: if the script compiles, then it means that the bug was fixed.
Since we reverse the logic, we then need the script to return a bad exit code! In case the script fails, we will return
a success (0) error code, because it means that the revision doesn&amp;#8217;t have the fix. Easy, but needs some mental contorsion :-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will note that this script uses &lt;code&gt;GROOVY_HOME&lt;/code&gt; and a local installation path. You can configure it using the &lt;code&gt;$HOME/.gradle/gradle.properties&lt;/code&gt; file,
and adding the following line in it:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;gradle.properties&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;groovy_installPath=/tmp/testversion&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, here is the groovy script which served as a test case (almost copied directly from the JIRA issue):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;bisect.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;abstract  class Base&amp;lt;A&amp;gt; {
    abstract  void foo(A[] a)
}

class X {}

class Inheritor extends Base&amp;lt;X&amp;gt;{
    @Override
    void foo(X[] a) {}
//Groovyc: Can&apos;t have an abstract method in a non-abstract class.
//The class &apos;B&apos; must be declared abstract
//or the method &apos;void foo([Ljava.lang.Object;)&apos; must be implemented.
}

Inheritor&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that each revision took around ~1 min 30s to test, even skipping the javadoc/groovydoc and indy versions of Groovy,
so you can imagine what benefit you have here in using automatic bisecting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, after around 20 minutes of automatic processing, I received this nice message:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;74d991f9f8c39d2730a054431bf28e6516e61735 is the first bad commit
commit 74d991f9f8c39d2730a054431bf28e6516e61735
Author: Cedric Champeau &amp;lt;cedric.champeau@gmail.com&amp;gt;
Date:   Sun Apr 27 18:06:24 2014 +0200

    GROOVY-6722: Compiler doesn&apos;t handle generic array covariant

:040000 040000 b61b92399ac86246c157f948b3232bf5ab0cf04f 5d0c56413a621c7693e7985aff0e4c84eb08889f M	src
bisect run success&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What? &quot;bad commit&quot;? Yes, remember that the logic is reversed, so &quot;bad&quot; means actually &quot;fixed it&quot;. So it says that the
first commit which &lt;strong&gt;fixed&lt;/strong&gt; the bug was actually &lt;code&gt;74d991f&lt;/code&gt;. And here we go, issue closed ;) One improvement I can see
is to use a local clone of my repository instead of working directly in the same repository, so that I can continue
working on my copy while bisecting is in progress.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>The new Groovy website</title>
      <link>https://melix.github.io/blog//2014/07/new-groovy-website.html</link>
      <pubDate>Fri, 18 Jul 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/07/new-groovy-website.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last week, we revealed the beta of a &lt;a href=&quot;https://beta.groovy-lang.org&quot;&gt;brand new website for the Groovy language&lt;/a&gt;. This
new website is &lt;a href=&quot;https://github.com/groovy/groovy-website&quot;&gt;open sourced&lt;/a&gt; and already received a few contributions.
In order to make it even easier and as it a fully statically generated site that makes use of Groovy
I wanted to give more technical details on the toolchain and how it is generated.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_static_website&quot;&gt;A static website&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the first questions which arised was: &lt;em&gt;why not use Grails/Spring Boot/Ratpack?&lt;/em&gt; In fact, the
new Groovy website is fully statically generated. It offers multiple advantages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;hosting is much easier, as it only consists of static pages and assets&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;maintenance is simplified, no database to backup for example&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;everything is self contained, pages and data, into a &lt;a href=&quot;https://github.com/groovy/groovy-website&quot;&gt;single repository&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;no need for authentication&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;all content is public&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, we didn&amp;#8217;t have any requirement for storing anything in a database, or that would
require dynamic generation. Pull requests are enough so far. Eventually, we&amp;#8217;re thinking about a
blog, but even that can be statically generated even if you want to allow users to comment on articles
(this blog is a perfect example). So in short, this decision was motivated by one mantra:
&lt;em&gt;the right tool for the right job&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The documentation, that you can find on &lt;a href=&quot;https://beta.groovy-lang.org/documentation.html&quot;&gt;this page&lt;/a&gt;, had
already started migrating from the aging wiki to . It is generated independently of the
website and integrated into it using iframes (we&amp;#8217;re thinking about source integration though).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_structure_of_the_project&quot;&gt;Structure of the project&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_generator_and_site&quot;&gt;Generator and site&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/groovy/groovy-website&quot;&gt;project&lt;/a&gt; is built using &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle 2&lt;/a&gt; and consists of 2 subprojects:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the &lt;a href=&quot;https://github.com/groovy/groovy-website/tree/master/generator&quot;&gt;generator&lt;/a&gt; project contains, as the name says,
the static generator. It makes use of a &lt;a href=&quot;#template-engine&quot;&gt;template engine&lt;/a&gt; and provides the classes used in the model
of the templates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;a href=&quot;https://github.com/groovy/groovy-website/tree/master/site&quot;&gt;site&lt;/a&gt; project contains the templates and data. If you&amp;#8217;re
looking into contributing contents, this is likely the place to look at.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Building and testing the site is easy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone https://github.com/groovy/groovy-website.git          &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
cd groovy-website
./gradlew generate                                              &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;clones the repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;generates the website from templates&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The output will be visible in &lt;code&gt;&amp;lt;project directory&amp;gt;/site/build/site&lt;/code&gt;. There&amp;#8217;s also a &lt;code&gt;checkDeadlinks&lt;/code&gt; tasks that we will
use once we get out of the beta phase to ensure that the generated pages do not contain any dead link.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Internally, we use our &lt;a href=&quot;https://ci.groovy-lang.org/viewType.html?buildTypeId=Groovy_Website&amp;amp;guest=1&quot;&gt;CI server&lt;/a&gt; to deploy
changes to the &lt;code&gt;master&lt;/code&gt; branch live. So any commit which is pushed onto the master branch is automatically published
(in general, takes less than 2 minutes).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_adding_contents&quot;&gt;Adding contents&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even if the site is statically generated, we still have data. In this project, there&amp;#8217;s an important file, named
&lt;a href=&quot;https://github.com/groovy/groovy-website/blob/master/site/src/site/sitemap.groovy&quot;&gt;sitemap.groovy&lt;/a&gt; which handles a lot
of the contents of the website. It is our &quot;low cost&quot; database and as you can see, it&amp;#8217;s a DSL describing the contents
of the website.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, you can see the &lt;code&gt;menu&lt;/code&gt; section which looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;menu {
    group(&apos;Groovy&apos;) {
        item &apos;Learn&apos;,                       &apos;learn.html&apos;
        item &apos;Documentation&apos;,               &apos;documentation.html&apos;
        item &apos;Download&apos;,                    &apos;download.html&apos;
        item &apos;Community&apos;,                   &apos;community.html&apos;
        item &apos;Ecosystem&apos;,                   &apos;ecosystem.html&apos;
    }

    group(&apos;About&apos;) {
        item &apos;Contributing&apos;,                &apos;contribute.html&apos;
        item &apos;Source code&apos;,                 &apos;https://github.com/groovy/groovy-core&apos;
        item &apos;Books&apos;,                       &apos;learn.html#books&apos;
        item &apos;Sponsors&apos;,                    &apos;sponsors.html&apos;
        item &apos;FAQ&apos;,                         &apos;faq.html&apos;
        item &apos;Search&apos;,                      &apos;search.html&apos;
    }

    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It is a purely declarative description of the site menus. Actually, the &quot;Groups&quot; are used in the footer of the page,
while the main &lt;code&gt;Groovy&lt;/code&gt; group is used to generate the top navigation bar. Using a simple descriptive DSL is very interesting,
because it decouples templates from the contents of the menu. We make sure that those templates do not contain any element
which is hardcoded and reduce the risks of forgetting to update the footer, for example, if a section is added.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The same file is used to describe the list of downloads:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;downloads {
    // ...
    distribution(&apos;Groovy 2.3&apos;) {
        description {
            yield &apos;Groovy 2.3 is our latest official &apos;
            a(href: &apos;versioning.html&apos;, &apos;version&apos;)
            yield &apos; of Groovy.&apos;
        }

        version(&apos;2.3.4&apos;) {
            stable true
            releaseNotes &apos;https://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&amp;amp;version=20432&apos;
            windowsInstaller &apos;https://dist.codehaus.org/groovy/distributions/installers/windows/nsis/groovy-2.3.4-installer.exe&apos;
        }
    }
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or the books which are listed on the &lt;a href=&quot;https://beta.groovy-lang.org/learn.html&quot;&gt;learn page&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;books {
    book(&apos;Groovy in Action, 2nd edition&apos;) {
        authors &quot;Dierk König, Guillaume Laforge, Paul King, Cédric Champeau, Hamlet D&apos;Arcy, Erik Pragt, and Jon Skeet&quot;
        cover &apos;img/books/regina.png&apos;
        url &apos;https://www.manning.com/koenig2/&apos;
        description &apos;The undisputed definitive reference on the Groovy programming language, authored by core members of the development team.&apos;
    }
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The same is done for all contents that need regular updates: user groups, events, projects of the ecosystem, &amp;#8230;&amp;#8203; I think
this DSL provides a very nice way to add contents to the website without caring about where it has to be done. You can
really think of it as a small database, but making use of a Groovy DSL.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition, this file also declares the &lt;a href=&quot;https://github.com/groovy/groovy-website/blob/03e3806cf26af6b13d99e6ee7473687e3f36fedd/site/src/site/sitemap.groovy#L62-L74&quot;&gt;mapping between pages in the documentation section&lt;/a&gt;
and &lt;a href=&quot;https://beta.groovy-lang.org/documentation.html&quot;&gt;the documentation page&lt;/a&gt;. Last but not least, it lists the individual
pages that the website contain. Those pages make use of the &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_eat_your_own_dog_food&quot;&gt;Eat your own dog food&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Groovy 2.3, we introduced a new &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt;. We decided that the new web site was an excellent showcase of
this template engine, and a real life use case. This template engine has several remarkable features, like static compilation
of templates (even if the model is dynamic), layouts and of course a human readable builder like syntax:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   head {
    title &apos;Groovy markup template engine in action!&apos;
   }
   body {
    ul {
        features.each { f-&amp;gt; li(f.name) }
    }
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It has already been integrated into &lt;a href=&quot;https://spring.io/blog/2014/05/28/using-the-innovative-groovy-template-engine-in-spring-boot&quot;&gt;Spring Boot&lt;/a&gt;
and &lt;a href=&quot;https://www.ratpack.io/&quot;&gt;Ratpack&lt;/a&gt; will use it in the next version (to be released on August 1st). A hint about its performance can be found &lt;a href=&quot;https://github.com/ratpack/ratpack/pull/370&quot;&gt;here&lt;/a&gt;.
If you are interested in details about how it works, you can find the documentation &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;here&lt;/a&gt;
and you can read my &lt;a href=&quot;https://melix.github.io/blog/2014/02/markuptemplateengine.html&quot;&gt;blog posts&lt;/a&gt; about it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The website subproject is therefore organized accordingly. Inside the &lt;a href=&quot;https://github.com/groovy/groovy-website/tree/master/site/src/site&quot;&gt;main source tree&lt;/a&gt;, you&amp;#8217;ll find the following directories:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;assets: contains static assets, like Javascript, CSS, images, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;html: contains pure HTML files which are easier to embed as is than using a markup syntax&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;includes: contains elements of code which are shared among multiple templates&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;layouts: contains template layouts, as defined in the &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html#_layouts&quot;&gt;documentation&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pages: contains the main pages of the website&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In general, consider &lt;code&gt;pages&lt;/code&gt; as the entry point. A page generally makes use of one layout. As an example, let&amp;#8217;s see how
the &lt;a href=&quot;https://beta.groovy-lang.org/ecosystem.html&quot;&gt;Ecosystem&lt;/a&gt; page is generated. The source file consists of this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;ecosystem.groovy&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;layout &apos;layouts/main.groovy&apos;, true,                                             &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    pageTitle: &apos;The Groovy programming language - Ecosystem&apos;,                   &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
    mainContent: contents {                                                     &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
      div(id: &apos;content&apos;, class: &apos;page-1&apos;) {
        section(class: &apos;row&apos;) {
          div(class: &apos;row-fluid&apos;) {
            // ... snip side menu ...
            div(class: &apos;col-lg-8 col-lg-pull-0&apos;) {
              include template: &apos;includes/contribute-button.groovy&apos;             &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
              h1 {
                i(class: &apos;fa fa-leaf&apos;) {}
                yield &apos; Ecosystem&apos;
              }
              p {
                yield &apos;&apos;&apos;
                    Beside the language and its API, Groovy gave birth   ...
                    on various themes such as web frameworks, desktop    ...
                    In this section, we will highlight a few of the most ...
                    which leverage Groovy at their core.
              &apos;&apos;&apos;
              }
              hr(class: &apos;divider&apos;)

              ecosys.eachWithIndex { e, index -&amp;gt;                                &lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
                def (name, item) = [e.key, e.value]
                article {
                  a(name: &quot;${name}&quot;) {}
                  div(class:&quot;content-heading clearfix media&quot;) {
                    div {
                      if (item.logo) {
                        img class: &quot;pull-${(index % 2 == 0) ? &apos;left&apos; : &apos;right&apos;}&quot;,
                          src: item.logo, alt: name, hspace: &apos;20px&apos;
                      } else {
                        h2(name)
                      }
                      p(item.description)
                    }
                    a(href: item.url, target:&apos;_blank&apos;, &quot;Learn more...&quot;)
                  }
                }
                hr(class: &apos;divider&apos;)
              }
              // ...
            }
          }
        }
      }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;make use of the &lt;code&gt;main&lt;/code&gt; layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;the layout requires a &lt;code&gt;pageTitle&lt;/code&gt; variable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;as well as a &lt;code&gt;mainContent&lt;/code&gt; section corresponding to the main page contents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;example of use of an &lt;code&gt;include&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;iterates over the &lt;code&gt;ecosys&lt;/code&gt; variable which contains the list of ecosystem projects as found in the sitemap&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, this template format has the advantage of taking care of generating markup for you. You won&amp;#8217;t hit your
head again on the wall to find an unclosed tag. Everything is embedded, readable and concise.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_lessons_learnt&quot;&gt;Lessons learnt&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using the &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt; for this project was interesting, because it was probably the first &quot;real life&quot; project
to use it intensively. And as such, we discovered usability issues, but also bugs. Hopefully, none of those bugs or
usability features were critical, and everything could be worked around, but expect some fixes in Groovy 2.3.5. It is
also the reason why the project initially used &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle 2&lt;/a&gt;: it comes with Groovy 2.3.2 which embeds the &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt;,
so it was possible to use it &lt;strong&gt;without&lt;/strong&gt; organizing the project into separate modules like we have. In fact, the early
versions of the site didn&amp;#8217;t use subprojects. It&amp;#8217;s only when we wanted to leverage improvements from Groovy 2.3.4 that
we had to &lt;a href=&quot;https://github.com/groovy/groovy-website/commit/e922701f747dbb78a7e695796c60d2b783f7e7ee&quot;&gt;switch to that architecture&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_team_work&quot;&gt;A team work&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, I can&amp;#8217;t finish this blog post without mentionning the team work it implied. In particular:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/oodamien&quot;&gt;Damien Vitrac&lt;/a&gt; designed the website and produced HTML sketches. If you think the new site
looks good, thank this guy!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/glaforge&quot;&gt;Guillaume Laforge&lt;/a&gt; designed the site architecture, wrote contents, tweaked the CSS, that is to
say produced almost all contents. He spent countless hours fixing responsiveness issues and digging into front-end dev.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/CedricChampeau&quot;&gt;I streamlined&lt;/a&gt; the process by setting up the Gradle project, designing the sitemap DSL,
the integration of the &lt;a href=&quot;https://beta.groovy-lang.org/docs/latest/html/documentation/markup-template-engine.html&quot;&gt;markup template engine&lt;/a&gt;, CI integration, &amp;#8230;&amp;#8203; that is to say pretty much all the &quot;backend&quot; stuff.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;, as a community, provided awesome &lt;a href=&quot;https://github.com/groovy/groovy-website/pulls?direction=desc&amp;amp;page=1&amp;amp;sort=created&amp;amp;state=closed&quot;&gt;pull requests&lt;/a&gt; within hours. Keep them coming, we love it!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each of us have different skills. Guillaume is far better than I am in any kind of web design, styling issues, etc for example, so in the
end, I think the combination works quite good and that the site as it is now is already pretty usable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let us know what you think, and don&amp;#8217;t forget that you can contribute, it&amp;#8217;s easy!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Contributing for the Groovy language: setting up IntelliJ IDEA</title>
      <link>https://melix.github.io/blog//2014/06/contribute-groovy-ide.html</link>
      <pubDate>Tue, 24 Jun 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/06/contribute-groovy-ide.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Often people ask us how you can setup a development environment to contribute on the Groovy project. If you use IntelliJ IDEA, it&amp;#8217;s actually very easy, so I decided to make a video for it. It&amp;#8217;s my first screencast ever, I think I will try to do more in the future, so please excuse my hesitations and enjoy! You&amp;#8217;ll notice that apparently Google Hangouts dislikes my face, but hopefully, the screensharing stuff worked ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here&amp;#8217;s the video:&lt;/p&gt;
&lt;/div&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/EhJa-Z8XDVw&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, you can ask me if you have issues with the setup, but it should really be straightforward!&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy on Android, technical details</title>
      <link>https://melix.github.io/blog//2014/06/grooid2.html</link>
      <pubDate>Tue, 10 Jun 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/06/grooid2.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my previous &lt;a href=&quot;https://melix.github.io/blog/2014/06/grooid.html&quot;&gt;post&lt;/a&gt;, I have introduced how we could now use the &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; to develop Android applications. In this post, I will give you more details about how it works internally, giving you more hints about what makes it possible.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_compiling_groovy&quot;&gt;Compiling Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; is a JVM language which compiles to bytecode. Even if it has scripting capabilities, it&amp;#8217;s always compiled. This means that in Groovy, you have two options: either a class is compiled to a &lt;code&gt;.class&lt;/code&gt; file and used like any other class file on the JVM, using the &lt;code&gt;groovyc&lt;/code&gt; compiler instead of &lt;code&gt;javac&lt;/code&gt;, or a class can be compiled &lt;strong&gt;at runtime&lt;/strong&gt;, for example if you rely on scripting. In the last case, the source script (or any Groovy source in general, not necessarily scripts) is available at runtime, and you rely on APIs that Groovy provide to compile those sources and execute them while your application is running. This is typical of scripting languages, but you must be aware that in any case, Groovy is &lt;strong&gt;not&lt;/strong&gt; an interpreted language: everything is turned into bytecode.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_a_classic_android_application&quot;&gt;A classic Android application&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since the Dalvik VM doesn&amp;#8217;t use the same bytecode as the JVM, Android requires a bit of work in order to compile and execute Java programs. A special tool, called &lt;em&gt;dex&lt;/em&gt;, is responsible for converting the JVM bytecode into Dalvik bytecode, and compile it into a &lt;code&gt;classes.dex&lt;/code&gt; file. This is illustrated in the following schema:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/compilation_process_normal.png&quot; alt=&quot;Classic Android compilation process&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In our case, we&amp;#8217;re using the Gradle build tool, which is now the default for Android projects, so Gradle is responsible for this chain. Java sources are compiled into &lt;code&gt;.class&lt;/code&gt; files, then those classes are processed by the &lt;code&gt;dex&lt;/code&gt; tool, which converts bytecode for all classes and packages everything into a &lt;code&gt;classes.dex&lt;/code&gt; file. Some additional steps can be done (such as calling ProGuard to reduce the size of the package), but in the end, an APK is produced, which is the deliverable application. When deployed on the device, there&amp;#8217;s nothing else to do than loading the classes and executing the application.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s see how the process differs in case of a Groovy application.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_an_application_written_in_groovy&quot;&gt;An application written in Groovy&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, we have &lt;code&gt;.groovy&lt;/code&gt; files, corresponding to Groovy sources, but we may also have &lt;code&gt;.java&lt;/code&gt; files. In the end, the process looks very similar:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/compilation_process_groovy.png&quot; alt=&quot;Groovy Android compilation process&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This schema exactly illustrates how the &lt;a href=&quot;https://github.com/melix/gr8confagenda&quot;&gt;GR8Conf Agenda&lt;/a&gt; application is compiled. All is done at &lt;strong&gt;compile time&lt;/strong&gt;, and nothing more at runtime. Groovy sources are compiled into JVM bytecode, which is in turn converted into Dalvik bytecode using &lt;code&gt;dex&lt;/code&gt;. There&amp;#8217;s absolutely no difference with Java, apart from the compiler, which is able to process both Groovy and Java sources!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One noticeable difference that some people have already reported to me is that since we embed the Groovy runtime, the number of method descriptors used in the &lt;code&gt;classes.dex&lt;/code&gt; file is significantly higher than with an application written in pure Java. From my early tests, a Groovy application would consume around 8k methods, without optimizations. The &lt;code&gt;classes.dex&lt;/code&gt; file has a limit of 65536 methods, so this is something you have to keep in mind. Anyway, I am not an Android specialist, but there seem to be workarounds available, like the &lt;code&gt;multi-dex&lt;/code&gt; option.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, Groovy is not different from any other library you would embed in your application, it&amp;#8217;s &quot;just&quot; an additional jar. I also mentionned the fact that I recommended to use &lt;code&gt;@CompileStatic&lt;/code&gt; on your classes. There&amp;#8217;s a good reason for that. If you don&amp;#8217;t, the classes that you will compile will use the &lt;strong&gt;dynamic runtime&lt;/strong&gt; of Groovy. This is unlikely what you want on a mobile application, especially because on Android, it would use reflection, implying a major performance drop. On a normal JVM, Groovy would use call site caching techniques, like generation of classes at runtime or invokedynamic to improve performance. This is &lt;strong&gt;not&lt;/strong&gt; possible on Android, so places where you use dynamic features of Groovy should be limited to small parts of the application, called not frequently. A good example would be the use of a builder for the UI. Builders are a very nice feature of Groovy, and for a UI, it would only be called once when the activity is loaded.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using &lt;code&gt;@CompileStatic&lt;/code&gt;, you will ensure that your classes are &lt;strong&gt;statically compiled&lt;/strong&gt;, meaning that all method calls are resolved at compile time, leading to dramatically improved performance, very close, if not equal, to that of Java (depending on how you write your code, as usual, because idiomatic Groovy might not always be the fastest implementation).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In any case, you must recall that the first application that I wrote does not use a single class generated at runtime. Even if you remove all &lt;code&gt;@CompileStatic&lt;/code&gt; annotations, it would use the dynamic runtime, but &lt;strong&gt;without&lt;/strong&gt; creating classes at runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_runtime_scripting&quot;&gt;Runtime scripting&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the difficulties of adapting the &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; is that, as we said, Groovy is a highly dynamic language. One of its capabilities is executing scripts at runtime. So what if we wanted to type a Groovy script on the device, and execute it directly on it? Is it possible? In fact, yes, it is possible, given that you follow this process:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/compilation_process_runtime.png&quot; alt=&quot;Groovy Android compilation process at runtime&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can have an application, written in Groovy or not, but in the end, &lt;strong&gt;once the application is running&lt;/strong&gt;, you have Groovy source code that you want to execute. Then it needs to compile the classes, call &lt;code&gt;dex&lt;/code&gt; &lt;strong&gt;directly on the device&lt;/strong&gt;, package the result into a &lt;code&gt;jar&lt;/code&gt; file on the local filesystem, then load it using a special classloader. So why this is possible, the process is very complex, not straightforward, but more importantly, it is dramatically slow.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This process is demonstrated in &lt;a href=&quot;https://github.com/melix/grooidshell-example&quot;&gt;this application&lt;/a&gt;, which replicates the behavior of the well-known &lt;a href=&quot;https://beta.groovy-lang.org/docs/groovy-2.3.2/html/documentation/#integ-groovyshell&quot;&gt;GroovyShell&lt;/a&gt; but directly on an Android device. To give you an idea, on my own device, a Samsung Galaxy Note 3, starting the application, written in Groovy, is blazing fast. Then if you hit the &quot;execute&quot; button, the first time, compilation of the little script will take around 3s.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;imageblock text-center&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;img src=&quot;/blog/img/groovy-scripting.png&quot; alt=&quot;Compiling Groovy at runtime&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Subsequent compilations take much less time (around ~500ms), but the fact of having to dex files and write them to the filesystem is a performance killer. In anycase, this shows that it is possible, and even that you could rely on it for an application that would handle scripts. It would be possible, for example, to cache the jar files in order to avoid recompiling them&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, I gave further details on how Groovy gets running onto an Android device. In a future post, I will give you more details about how you can get started with your own project. I will maybe give &lt;a href=&quot;https://github.com/pledbrook/lazybones&quot;&gt;Lazybones&lt;/a&gt;, a project bootstraping tool, more love in the next days ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy on Android</title>
      <link>https://melix.github.io/blog//2014/06/grooid.html</link>
      <pubDate>Thu, 5 Jun 2014 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2014/06/grooid.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yesterday ended &lt;a href=&quot;https://gr8conf.eu&quot;&gt;GR8Conf Europe&lt;/a&gt;, a &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; conference in Copenhagen that was once again a successful event.
I want to thank the crew again for this, and of course the &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; community which is so friendly and always helpful. This year
turned out to be very special for me, because just two days after the announcement by Apple of the &lt;a href=&quot;https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html&quot;&gt;Swift language&lt;/a&gt;, I was talking about
running Groovy on Android! As Guillaume Laforge &lt;a href=&quot;https://glaforge.appspot.com/article/apple-s-swift-programming-language-inspired-by-groovy&quot;&gt;noticed&lt;/a&gt;, there
are a lot of similarities between the &lt;a href=&quot;https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html&quot;&gt;Swift language&lt;/a&gt; and &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The timing is almost perfect, because Android users will want to have a language which is as modern as Swift is, but running on Android. And I see no
better candidate than &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; here.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_presentation&quot;&gt;The presentation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Should you be interested in the slides, you can find them below. Since it was presented at &lt;a href=&quot;https://gr8conf.eu&quot;&gt;GR8Conf Europe&lt;/a&gt;, it gives a bit of history of the changes needed to
have the runtime working on Android too:&lt;/p&gt;
&lt;/div&gt;
&lt;script async class=&quot;speakerdeck-embed&quot; data-id=&quot;e8e58fc0cdee0131f20616308848c4b8&quot; data-ratio=&quot;1.6&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For those of you who are new to Groovy, you have to know that this language is derived from Java, meaning that the learning curve is almost 0, but it also
removes a lot of its verbosity and adds a lot of features to it, such as closures (similar to lambdas in Java 8, but Java 8 is not available for Android
developers), builders, runtime and compile-time metaprogramming.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As an example of how Groovylang can be used to reduce the verbosity of Java on Android, I will take a simple example: asynchronous tasks. Asynchronous tasks
are required as soon as a task takes too much time to be executed on the UI thread. That is the case, by default, for any network based operations, in order
to guarantee that the UI remains snappy even if network is slow or unavailable. The problem is that those asynchronous tasks are incredibly verbose. You have
to write a lot of code, that I would tend to name &quot;inner class hell&quot;, just for this. Let&amp;#8217;s imagine that you need to parse a JSON feed, then update the UI
accordingly. Then you would have to write something like this (no kidding):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public class FeedActivity {
    TextView mTextView;

    ...

    void updateFeed() {
    	new FeedTask().execute(&quot;https://path/to/feed&quot;);
    }

    class FeedTask extends AsyncTask&amp;lt;String, Void, String&amp;gt; {
        protected String doInBackground(String... params) {
            DefaultHttpClient httpclient = new DefaultHttpClient(new BasicHttpParams());
            HttpPost httppost = new HttpPost(params[0]);

            InputStream inputStream = null;
            String result = null;
            try {
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();

                inputStream = entity.getContent();
                // json is UTF-8 by default
                BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, &quot;UTF-8&quot;), 8);
                StringBuilder sb = new StringBuilder();

                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append(&quot;\n&quot;);
                }
                result = sb.toString();
            } catch (Exception e) {
                // Oops
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (Exception squish) {
                }
            }
            StringBuilder speakers = null;
            try {
                JSONObject jObject = new JSONObject(result);
                JSONArray jArray = jObject.getJSONArray(&quot;speakers&quot;);
                speakers = new StringBuilder();
                for (int i = 0; i &amp;lt; jArray.length(); i++) {
                    speakers.append(jArray.getString(i));
                    speakers.append(&quot; &quot;);
                }
            } catch (JSONException e) {
                // do something?
            }
            return speakers.toString();
        }

        @Override
        protected void onPostExecute(String s) {
            mTextView.setText(s);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So now, let&amp;#8217;s see the equivalent in Groovy (no kidding either):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public class FeedActivity {
    TextView mTextView

    ...

    void updateFeed() {
    	Fluent.async {
            def json = new JsonSlurper().parse([:], new URL(&apos;https://path/to/feed&apos;), &apos;utf-8&apos;)
            json.speakers.join(&apos; &apos;)
        } then {
	    mTextView.text = it
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think you can start to see the advantage of using Groovy in your own Android projects. Of course, the &lt;code&gt;Fluent&lt;/code&gt; class that I&amp;#8217;m using here
is a support class which I implemented in my &lt;a href=&quot;https://github.com/melix/gr8confagenda&quot;&gt;first Android project&lt;/a&gt; (which is open sourced btw), but it&amp;#8217;s
really simple and gives an example of how Android users could benefit from Groovification of their APIs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_feeling_the_pain&quot;&gt;Feeling the pain&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is actually a key point of my talk: I hadn&amp;#8217;t written any Android application before this talk, and I definitely wanted to be able to write
an application in Groovy on Android. Why? Because it&amp;#8217;s been some time already that I use Groovy everyday, and there&amp;#8217;s no turning back. I wanted
to feel the pain of the Java developers on Android, so that I can write better tools for them. And that&amp;#8217;s actually where you, as a user, come
in action: there are so many Groovy libraries out there whose sole objective is to ease the pain, make things that shouldn&amp;#8217;t be complicated a breeze.
This is exactly the point. My example with &lt;code&gt;Fluent&lt;/code&gt; is &lt;strong&gt;one&lt;/strong&gt; example of simplification of usages of Android APIs, but you have many more to invent,
especially because &lt;strong&gt;you&lt;/strong&gt; must have been as annoyed as I did by all those asynchronous tasks, XML files (think of builders!), callback hell, etc&amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_beginning_of_a_new_era&quot;&gt;The beginning of a new era&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In upcoming posts, I will try to demonstrate that we&amp;#8217;re just at the beginning. Some people are already asking for a {swift} alternative for Android.
It&amp;#8217;s there guys, you have it, so spread the word and let&amp;#8217;s make it happen! I am convinced that it is the beginning of a new era for Android and Groovy.
Google already switched their main build system to Gradle, which is, by the way, using Groovy, so I think it&amp;#8217;s time to move over and show your love!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All you need to get started is explained in the slide deck above, and you can find the source code of the sample android application on GitHub:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/melix/gr8confagenda&quot; class=&quot;bare&quot;&gt;https://github.com/melix/gr8confagenda&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_update_3_its_even_simpler_now&quot;&gt;Update 3: it&amp;#8217;s even simpler now&lt;/h3&gt;
&lt;div class=&quot;admonitionblock tip&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-tip&quot; title=&quot;Tip&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Groovy 2.4.0 has been released now and building an Android application in Groovy is even simpler. All you have to do is to apply a Gradle plugin. Instructions can be found &lt;a href=&quot;https://github.com/groovy/groovy-android-gradle-plugin&quot;&gt;here&lt;/a&gt;. You absolutely don&amp;#8217;t have to build Groovy from sources or add tasks to your Gradle build as described originally in this post! Just &lt;a href=&quot;https://github.com/groovy/groovy-android-gradle-plugin&quot;&gt;use the plugin&lt;/a&gt;!
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock warning&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-warning&quot; title=&quot;Warning&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Information below is outdated. Please use the &lt;a href=&quot;https://github.com/groovy/groovy-android-gradle-plugin&quot;&gt;Gradle plugin !&lt;/a&gt;.
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Update 2: build instructions with the Gradle plugin&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can now use a Gradle plugin to integrate Groovy with Android. The plugin can be found here: &lt;a href=&quot;https://github.com/melix/groovy-android-gradle-plugin&quot;&gt;groovy-android-gradle-plugin&lt;/a&gt;. As of version 0.2, the plugin supports the Android plugin 0.10+.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Update: build instructions&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you want to try it by yourself, here&amp;#8217;s how you can do it. First of all, official support for Android will be in Groovy 2.4. Before the first beta,
you&amp;#8217;ll have to build it from sources, and here is the quickest way:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone https://github.com/melix/groovy-core.git --branch master
cd groovy-core
./gradlew -PskipIndy=true install&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you can clone the sample application:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;cd ..
git clone https://github.com/melix/gr8confagenda.git&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This contains a project that you can open using &lt;a href=&quot;https://developer.android.com/sdk/installing/studio.html&quot;&gt;Android Studio&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you want to use the &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt; in your own Android project, a requirement is that it is using Gradle. If so, you can update your &lt;code&gt;build.gradle&lt;/code&gt; file
as is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;android {
   ...
   packagingOptions {
        // workaround for https://stackoverflow.com/questions/20673625/android-gradle-plugin-0-7-0-duplicate-files-during-packaging-of-apk
        exclude &apos;META-INF/LICENSE.txt&apos;
        exclude &apos;META-INF/groovy-release-info.properties&apos;
    }
}

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
    compile &apos;org.codehaus.groovy:groovy:2.4.0-SNAPSHOT:grooid&apos;
    // the following dependency is necessary if you want JSON support
    compile (&apos;org.codehaus.groovy:groovy-json:2.4.0-SNAPSHOT&apos;) {
        transitive = false
    }
}

// add support for Groovy to existing configurations
android.applicationVariants.all {
    task &quot;groovy${name}Compile&quot;(type: GroovyCompile) {
        source = javaCompile.source + fileTree(&apos;src/main/java&apos;).include(&apos;**/*.groovy&apos;)
        destinationDir = javaCompile.destinationDir
        classpath = javaCompile.classpath
        groovyClasspath = classpath
        sourceCompatibility = &apos;1.6&apos;
        targetCompatibility = &apos;1.6&apos;
        doFirst {
            def runtimeJars = plugins.findPlugin(com.android.build.gradle.AppPlugin).runtimeJars
            classpath = files(runtimeJars) + classpath
        }
    }
    javaCompile.dependsOn(&quot;groovy${name}Compile&quot;)
    javaCompile.enabled = false
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And that&amp;#8217;s all! Now, one option for you is to write support libraries and make them available to the community. Enjoy!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A fast markup template engine for Groovy (part 2 of 2)</title>
      <link>https://melix.github.io/blog//2014/02/markuptemplateengine_part2.html</link>
      <pubDate>Tue, 18 Feb 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/02/markuptemplateengine_part2.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, I will discuss the implementations details for the markup template engine I have described in a &lt;a href=&quot;/blog/2014/02/markuptemplateengine.html&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_compiling_templates&quot;&gt;Compiling templates&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_markuptemplateengine_class&quot;&gt;The MarkupTemplateEngine class&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Even if my first implementation of the markup template engine was relying on &lt;code&gt;StreamingMarkupBuilder&lt;/code&gt;, the technique used to compile templates into bytecode is actually the same after all optimizations. It relies on:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a &lt;a href=&quot;https://groovy.codehaus.org/api/groovy/lang/GroovyClassLoader.html&quot;&gt;GroovyClassLoader&lt;/a&gt; to create and cache template classes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a &lt;a href=&quot;https://groovy.codehaus.org/api/org/codehaus/groovy/control/CompilerConfiguration.html&quot;&gt;CompilerConfiguration&lt;/a&gt; to customize compilation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The various template engines that Groovy provide extend the &lt;a href=&quot;https://groovy.codehaus.org/api/groovy/text/TemplateEngine.html&quot;&gt;TemplateEngine&lt;/a&gt; class. All template engines must implement the &lt;code&gt;createTemplate&lt;/code&gt; method which returns an instance of &lt;a href=&quot;https://groovy.codehaus.org/api/groovy/text/Template.html&quot;&gt;Template&lt;/a&gt;. My first idea, here, was therefore to have a template engine which holds a &lt;code&gt;GroovyClassLoader&lt;/code&gt;, and compiles scripts as &lt;code&gt;Template&lt;/code&gt; instances. For thread safety reasons and to avoid compiling the same template again and again, I instead chose a slightly different approach, which is to compile the scripts, and cache the resulting class into a field of the &lt;code&gt;StreamingMarkupBuilderTemplate&lt;/code&gt; class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;    private class StreamingMarkupBuilderTemplate implements Template {
        final Class&amp;lt;BaseTemplate&amp;gt; templateClass;							&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;

        public StreamingMarkupBuilderTemplate(final Reader reader) {
            templateClass = groovyClassLoader.parseClass(
		new GroovyCodeSource(reader, &quot;GeneratedMarkupTemplate&quot; + counter.getAndIncrement(), &quot;&quot;));
        }

        public StreamingMarkupBuilderTemplate(final URL resource) throws IOException {
            templateClass = groovyClassLoader.parseClass(new GroovyCodeSource(resource));
        }

        public Writable make() {
            return make(Collections.emptyMap());							&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
        }

        public Writable make(final Map binding) {
            return DefaultGroovyMethods.newInstance(templateClass,
		new Object[]{MarkupTemplateEngine.this, binding, templateConfiguration});		&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
        }
    }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;templateClass&lt;/code&gt; corresponds to the user script, compiled as a template class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;make&lt;/code&gt; binds a model to the template&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;make&lt;/code&gt; instantiates a new template and binds the model to it&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;bind&lt;/code&gt; method is very important. It returns a &lt;code&gt;Writable&lt;/code&gt; which will trigger template rendering when &lt;code&gt;writeTo&lt;/code&gt; is called. Therefore, nothing is rendered until the &lt;code&gt;Writable#writeTo&lt;/code&gt; method is called. The only thing that &lt;code&gt;bind&lt;/code&gt; does is instantiating a new template. As we are using a cached class, there&amp;#8217;s no compilation involved anymore, so the template is compiled once for all.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_basetemplate_class&quot;&gt;The BaseTemplate class&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, the user script is compiled into a class which extends &lt;code&gt;BaseTemplate&lt;/code&gt;. This means that the following script:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;page.tpl&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;html {
   body {
      p(&quot;I&apos;m a template&quot;)
   }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;compiles to a class extending &lt;code&gt;BaseTemplate&lt;/code&gt;. If you are familiar with &lt;code&gt;GroovyClassLoader&lt;/code&gt; or &lt;code&gt;GroovyShell&lt;/code&gt;, you should actually know that normally, a script compiles to a class extending &lt;a href=&quot;https://groovy.codehaus.org/api/groovy/lang/Script.html&quot;&gt;Script&lt;/a&gt;. In our case, we don&amp;#8217;t want to extend &lt;code&gt;Script&lt;/code&gt;, because it does things that we don&amp;#8217;t want, such as overriding &lt;code&gt;getProperty&lt;/code&gt; or using a &lt;code&gt;Binding&lt;/code&gt; class, or even having the semantics of a Groovy script. Furthermore, it doesn&amp;#8217;t allow us to have a custom constructor to have private final fields. So the first step of our compilation process is actually to change the super class of the compiled script. The next step is to create a constructor that takes our model and the template configuration as parameters, as seen in the &lt;code&gt;make&lt;/code&gt; method. Last but not least, since the script being compiled defines a &lt;code&gt;run&lt;/code&gt; method (which is abstract in &lt;code&gt;Script&lt;/code&gt;) corresponding to the script body, we will perform additional code transformations on this specific method.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@Override
    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
        if (classNode.isScriptBody()) {							&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
            classNode.setSuperClass(MarkupTemplateEngine.BASETEMPLATE_CLASSNODE);	&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
            createConstructor(classNode);						&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
            transformRunMethod(classNode, source);					&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;a Groovy script may contain multiple class, so we need to check if the current class is actually the script body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we change the super class from &lt;code&gt;Script&lt;/code&gt; to &lt;code&gt;BaseTemplate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we create a new constructor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we perform code modifications on the script body&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_implementing_the_builder&quot;&gt;Implementing the builder&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;code&gt;transformRunMethod&lt;/code&gt; method is actually an example of how to implement a Groovy DSL using AST transformations. The goal of this method is to alter the AST (abstract syntax tree), so that some method calls in source code, for example, are actually rewritten. It is also the starting point of performance optimizations. This is actually very important. For example, one of the transformations will change:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(text)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;into:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(getModel().get(&quot;text&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Technically speaking, there is no need to do such a change: we could rely on &lt;code&gt;BaseTemplate&lt;/code&gt; implementing &lt;code&gt;propertyMissing&lt;/code&gt; to resolve missing variables (here, &lt;code&gt;text&lt;/code&gt;) and delegate the call to its internal &lt;code&gt;model&lt;/code&gt; field. However, this can be particularily slow, especially in builders where there are lots of nested closures, which involve a very long call chain. By doing this change, we transform a so-called &lt;code&gt;DynamicVariable&lt;/code&gt; (&lt;code&gt;text&lt;/code&gt;) into something that can be resolved statically (&lt;code&gt;getModel&lt;/code&gt; is declared in &lt;code&gt;BaseTemplate&lt;/code&gt; and is of type &lt;code&gt;Map&lt;/code&gt;). Slowly, we&amp;#8217;re making a switch towards &lt;strong&gt;statically compilable&lt;/strong&gt; code&amp;#8230;&amp;#8203; but we&amp;#8217;re not there yet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In classic builder code, compiling this would work and eventually, when the &lt;code&gt;p&lt;/code&gt; method is called, the meta-object protocol goes into action and eventually calls the &lt;code&gt;methodMissing&lt;/code&gt; method on the &lt;code&gt;BaseTemplate&lt;/code&gt; class if it is defined. So to make our code work, all we have to do is to write that method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;BaseTemplate.java&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;    public Object methodMissing(String tagName, Object args) throws IOException {
        Object o = model.get(tagName);
        if (args instanceof Object[]) {
            final Writer wrt = out;
            TagData tagData = new TagData(args).invoke();
            Object body = tagData.getBody();
            writeIndent();
            wrt.write(&apos;&amp;lt;&apos;);
            wrt.write(tagName);
            writeAttributes(tagData.getAttributes());
            if (body != null) {
                wrt.write(&apos;&amp;gt;&apos;);
                writeBody(body);
                writeIndent();
                wrt.write(&quot;&amp;lt;/&quot;);
                wrt.write(tagName);
                wrt.write(&apos;&amp;gt;&apos;);
            } else {
                if (configuration.isExpandEmptyElements()) {
                    wrt.write(&quot;&amp;gt;&amp;lt;/&quot;);
                    wrt.write(tagName);
                    wrt.write(&apos;&amp;gt;&apos;);
                } else {
                    wrt.write(&quot;/&amp;gt;&quot;);
                }
            }
        }
        return this;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can test that this code works by rendering a simple template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

def tplConf = new TemplateConfiguration()
MarkupTemplateEngine engine = new MarkupTemplateEngine(this.class.classLoader, tplConf)

def mkpTemplate = engine.createTemplate &apos;&apos;&apos;
html {
    body {
	p(text)
    }
}
&apos;&apos;&apos;
def model = [text:&apos;It works!&apos;]
mkpTemplate.make(model).writeTo(new PrintWriter(System.out))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is nice is that we can also rely on the template configuration to perform different transformations. For example, there&amp;#8217;s an optional &lt;code&gt;autoEscape&lt;/code&gt; flag which tells if variables read from the model should be automatically escaped. If the flag is set to false, the following code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;text&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;is transformed into:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;getModel().get(&quot;text&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;but if the flag is set to true, the generated code is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;yield(getModel().get(&quot;text&quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;where &lt;code&gt;yield&lt;/code&gt; is the method which will escape contents&amp;#8230;&amp;#8203; So it&amp;#8217;s a very flexible way to perform parametrized transformations of templates! The same technique is used to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;transform &lt;code&gt;include (template|escaped|unescaped):&apos;path/to/template&apos;&lt;/code&gt; into `include(Groovy|Escaped|Unescaped)(&apos;/path/to/template&apos;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;transform &lt;code&gt;unescaped.foo&lt;/code&gt; into &lt;code&gt;getModel().get(&quot;foo&quot;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;transform &lt;code&gt;&apos;:XXX&apos;()&lt;/code&gt; method calls into &lt;code&gt;methodMissing(&apos;XXX&apos;, &amp;#8230;&amp;#8203;)&lt;/code&gt;. This gives a way to render tags which have the same name as helper methods like &lt;code&gt;yield&lt;/code&gt;. In that case, the user can write &lt;code&gt;&apos;:yield&apos;()&lt;/code&gt; to create a tag &lt;code&gt;&amp;lt;yield&amp;gt;&lt;/code&gt; instead of calling the &lt;code&gt;yield&lt;/code&gt; method for example.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_statically_compiling_templates&quot;&gt;Statically compiling templates&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_oops_i_did_it_again&quot;&gt;Oops, I did it again!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Going further towards statically compilable code requires additional trickery. In the previous example, we still have a call (&lt;code&gt;p(&amp;#8230;&amp;#8203;)&lt;/code&gt;) which is &lt;em&gt;unresolved&lt;/em&gt;, goes through the MOP and eventually calls &lt;code&gt;methodMissing&lt;/code&gt;. The same way we converted the &lt;code&gt;text&lt;/code&gt; variable into a dynamic call, we can make it statically compilable. Since the method which would eventually be called would be &lt;code&gt;methodMissing&lt;/code&gt;, instead of going through the MOP, since we know that this particular method will always be called in our case, we can directly make the change, and hardwire it. The resulting code would look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;methodMissing(&quot;p&quot;, new Object[]{getModel().get(&quot;text&quot;)})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This change can be made in our transformer, like we did the &lt;code&gt;getModel&lt;/code&gt; change. However, we will see that we have a serious problem with that. Meanwhile, let&amp;#8217;s show how we can trigger static compilation of templates. This can be done easily by injecting the &lt;code&gt;@CompileStatic&lt;/code&gt; annotation through &lt;code&gt;CompilerConfiguration&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;compilerConfiguration.addCompilationCustomizers(new TemplateASTTransformer(tplConfig)); 		&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
compilerConfiguration.addCompilationCustomizers(
                new ASTTransformationCustomizer(CompileStatic.class));					&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;apply the AST transformations to rewrite unresolved variables and method missing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;apply &lt;code&gt;@CompileStatic&lt;/code&gt; to the template&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We can try the template engine using the same code as before:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

def tplConf = new TemplateConfiguration()
MarkupTemplateEngine engine = new MarkupTemplateEngine(this.class.classLoader, tplConf)

def mkpTemplate = engine.createTemplate &apos;&apos;&apos;
html {
    body {
    p(text)
    }
}
&apos;&apos;&apos;
def model = [text:&apos;It works!&apos;]
mkpTemplate.make(model).writeTo(new PrintWriter(System.out))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And it works! So what is the problem? Actually, there are multiple issues. The first one is that you can&amp;#8217;t call existing methods anymore! For example, we can&amp;#8217;t call the &lt;code&gt;yield&lt;/code&gt; method because it has been converted too:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;yield &apos;Some text&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;gets converted into:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;methodMissing(&quot;yield&quot;, new Object[] {&quot;Some &amp;lt;text to escape&amp;gt;&quot;})&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and eventually generates this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;xml&quot;&gt;&amp;lt;yield&amp;gt;Some &amp;lt;text to escape&amp;gt;&amp;lt;/yield&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Is it the end of the story? Can&amp;#8217;t we really statically compile our templates and make them super fast? Well, no, of course!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is where all the magic begins. Solving this problem requires being able to make a difference between calls to methods which &lt;strong&gt;exist&lt;/strong&gt; (like &lt;code&gt;yield&lt;/code&gt;) and calls to methods which are not defined (like &lt;code&gt;html&lt;/code&gt;). And guess what, Groovy has a very nice tool whose responsability is &lt;strong&gt;exactly&lt;/strong&gt; this: static type checking and by extension, static compilation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So let&amp;#8217;s start by removing the code which transforms the method calls into &lt;code&gt;methodMissing&lt;/code&gt; calls, and try to compile the following template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

def tplConf = new TemplateConfiguration()
MarkupTemplateEngine engine = new MarkupTemplateEngine(this.class.classLoader, tplConf)

def mkpTemplate = engine.createTemplate &apos;&apos;&apos;
html {
    body {
        yield text
    }
}
&apos;&apos;&apos;
def model = [text:&apos;Text &amp;lt;to be escaped&amp;gt;&apos;]
mkpTemplate.make(model).writeTo(new PrintWriter(System.out))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since we kept static compilation, it will fail, but it will give us interesting information:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[Static type checking] - Cannot find matching method GeneratedMarkupTemplate6#html(groovy.lang.Closure). Please check if the declared type is right and if the method exists.
 at line: 2, column: 1

[Static type checking] - Cannot find matching method GeneratedMarkupTemplate6#body(groovy.lang.Closure). Please check if the declared type is right and if the method exists.
 at line: 3, column: 5&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What we see is that the two errors are precisely the methods that we want to directly wire to &lt;code&gt;methodMissing&lt;/code&gt;. The &lt;code&gt;yield&lt;/code&gt; method has been recognized, so the type checker did the job for us. It is telling us: &quot;ok guys, there are two method calls I know nothing about. Those are &lt;code&gt;html&lt;/code&gt; and &lt;code&gt;body&lt;/code&gt;. Please do something or I can&amp;#8217;t compile it.&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s nice, but how can I help the compiler?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_type_checking_extensions&quot;&gt;Type checking extensions&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, this is precisely why type checking extensions were added in Groovy 2.1. They allow the programmer to help the compiler when he knows about a method call that the type checker isn&amp;#8217;t able to resolve. You can give hints and tell &quot;ok, this method exists, and it returns an object of type Foo&quot;. In Groovy 2.2, this mechanism was extended to static compilation, which opens another chapter in the incredible extensibility that Groovy has to offer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Writing type checking extensions require a bit of knowledge of the Groovy AST (abstract syntax tree), so anyone who ever wrote an AST transformation in Groovy should be capable of writing a type checking extension. Actually, it is even easier, and the process is described &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Type+checking+extensions&quot;&gt;here&lt;/a&gt;. In our case, we will start leveraging a feature of Groovy 2.2 will allows us to mix dynamic code with statically compiled code. That is to say that the only thing that our extension is going to do is saying &quot;when you don&amp;#8217;t know what a method call does, perform a dynamic invocation&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When we added this to Groovy 2.2, we really didn&amp;#8217;t want to make &quot;mixed&quot; mode a first class citizen in static compilation, because it defeats the idea of catching typos, which is one of the things people expect most from a type checking system. So this &quot;mixed&quot; mode is actually activated by type checking extensions. This means that the only method calls which will be made dynamic will be those that the programmer knows about, and really wants to convert to dynamic calls. It is an important difference, because we want the developper to be &lt;strong&gt;aware&lt;/strong&gt; of what he is doing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That said, how can we implement that? It&amp;#8217;s actually pretty easy. The first thing to do is to write the code which will help the compiler:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;methodNotFound { receiver, name, argList, argTypes, call -&amp;gt;	&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    if (call.lineNumber &amp;gt; 0) {					&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
        if (call.implicitThis) {				&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
            return makeDynamic(call, OBJECT_TYPE)		&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;react to the &lt;code&gt;methodNotFound&lt;/code&gt; event, thrown by the type checker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;make sure the event is called on user code, that is to say code for which there&amp;#8217;s an associated line number&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;make sure that only calls which are on an &quot;implicit this&quot; are made dynamic (see below)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;instruct the compiler to perform a dynamic call here&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Point 3 is actually important. We said that we wanted the developper to be aware of which calls he want to make dynamic. This is the kind of guards that you might want to add. In builder-style code, only method calls for which there&amp;#8217;s no explicit receiver should be considered as method creating tags. For example, if you write &lt;code&gt;this.foo&lt;/code&gt;, there is an &lt;strong&gt;explicit&lt;/strong&gt; &lt;code&gt;this&lt;/code&gt; receiver, and we don&amp;#8217;t want to convert that call. Instead, we want to let the compiler report an error.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that the extension is written, we still have to load it. There are two ways of loading type checking extensions: using scripts (Groovy 2.1) or precompiled type checking extensions (Groovy 2.2+). In my case, I wanted to use precompiled type checking extensions, to avoid paying the cost of compiling the type checking extension at runtime. This can be done by wrapping the extension script into a class extending &lt;code&gt;GroovyTypeCheckingExtensionSupport.TypeCheckingDSL&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class MarkupTemplateTypeCheckingExtension extends GroovyTypeCheckingExtensionSupport.TypeCheckingDSL {

    @Override
    Object run() {
	methodNotFound { receiver, name, argList, argTypes, call -&amp;gt;
		...
	}
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the extension can be loaded by slightly changing the way we activate &lt;code&gt;@CompileStatic&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;compilerConfiguration.addCompilationCustomizers(
        new ASTTransformationCustomizer(
            Collections.singletonMap(&quot;extensions&quot;,&quot;groovy.text.markup.MarkupTemplateTypeCheckingExtension&quot;), &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
            CompileStatic.class));									     &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;create the map of arguments for the &lt;code&gt;@CompileStatic&lt;/code&gt; AST transformation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;apply &lt;code&gt;@CompileStatic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_improving_performance&quot;&gt;Improving performance&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the type checking extension, we&amp;#8217;ve now instructed the compiler to perform &lt;strong&gt;dynamic&lt;/strong&gt; calls when it finds tag methods. All other calls, which were resolved statically, are made static. This is nice, but we are still paying the price of the meta-object protocol here, and there&amp;#8217;s no reason to go through a dynamic path were we want the target method to be &lt;code&gt;methodMissing&lt;/code&gt; in any case. So, how can we solve that?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;admonitionblock warning&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td class=&quot;icon&quot;&gt;
&lt;i class=&quot;fa icon-warning&quot; title=&quot;Warning&quot;&gt;&lt;/i&gt;
&lt;/td&gt;
&lt;td class=&quot;content&quot;&gt;
Before going further, you have to be warned. What I am going to show you is things that I wouldn&amp;#8217;t recommand for beginners in AST transformations. We&amp;#8217;re going to update the AST &lt;strong&gt;just before it is going to generate bytecode&lt;/strong&gt;. This is very late in the compilation process, meaning that you are walking along a thin rope without net! Traditional AST transformations run much earlier in the compilation process, and the compiler will do a lot of things for you (like resolving methods, variables, &amp;#8230;&amp;#8203;). Here, it is so late that all those things have already been done, so you have to do it all yourself!
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let the fun begin! The idea is quite simple actually. Instead of relying on &lt;code&gt;makeDynamic&lt;/code&gt;, we will transform the calls into direct calls to &lt;code&gt;methodMissing&lt;/code&gt;. The type checking extension API doesn&amp;#8217;t let you do this (it&amp;#8217;s not meant to transform the AST), so you have to do it yourself. This involves multiple steps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;when we start visiting a method, create an empty list of method calls that will need to be transformed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;when an unresolved call is found and that it matches our criteria, put that call into the list&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;after the method has been visited, trigger a transformer which will transform all calls in the list&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first step requires an extra block:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;beforeVisitMethod {		&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
   newScope {			&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
      builderCalls = []		&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we&amp;#8217;re entering a new method body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;newScope&lt;/code&gt; pushes a &quot;type checking scope&quot; on stack, where you can put user data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;add the &lt;code&gt;builderCalls&lt;/code&gt; method to this scope&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you can add the method calls to be transformed this way:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;methodNotFound { receiver, name, argList, argTypes, call -&amp;gt;
    if (call.lineNumber &amp;gt; 0) {
        if (call.implicitThis) {
            currentScope.builderCalls &amp;lt;&amp;lt; call
            return makeDynamic(call, OBJECT_TYPE)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And triggering the AST transformation can be done in an &lt;code&gt;afterVisitMethod&lt;/code&gt; block:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;afterVisitMethod { mn -&amp;gt;							&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
   scopeExit {									&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
      new BuilderMethodReplacer(context.source, builderCalls).visitMethod(mn)	&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;when we exit a method body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;pop the current scope from stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;trigger an AST transformation which will visit this method knowing which calls need to be transformed&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, we still miss the transformation code. For that, we need a class which extends &lt;a href=&quot;https://groovy.codehaus.org/api/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.html&quot;&gt;ClassCodeExpressionTransformer&lt;/a&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;    private static class BuilderMethodReplacer extends ClassCodeExpressionTransformer {

        private static final MethodNode METHOD_MISSING = ClassHelper.make(BaseTemplate).getMethods(&apos;methodMissing&apos;)[0]		&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;

        private final SourceUnit unit;
        private final Set&amp;lt;MethodCallExpression&amp;gt; callsToBeReplaced;

        BuilderMethodReplacer(SourceUnit unit, Collection&amp;lt;MethodCallExpression&amp;gt; calls) {
            this.unit = unit
            this.callsToBeReplaced = calls as Set;
        }

        @Override
        protected SourceUnit getSourceUnit() {
            unit
        }

        @Override
        void visitClosureExpression(final ClosureExpression expression) {
            super.visitClosureExpression(expression)
        }

        @Override
        public Expression transform(final Expression exp) {
            if (callsToBeReplaced.contains(exp)) {									&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
                def args = exp.arguments instanceof TupleExpression ? exp.arguments.expressions : [exp.arguments]
                args*.visit(this)
                // replace with direct call to methodMissing
                def call = new MethodCallExpression(									&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
                        new VariableExpression(&quot;this&quot;),
                        &quot;methodMissing&quot;,
                        new ArgumentListExpression(
                                new ConstantExpression(exp.getMethodAsString()),
                                new ArrayExpression(
                                        OBJECT_TYPE,
                                        [* args]
                                )
                        )
                )
                call.implicitThis = true
                call.safe = exp.safe
                call.spreadSafe = exp.spreadSafe
                call.methodTarget = METHOD_MISSING									&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
                call													&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
            } else if (exp instanceof ClosureExpression) {
                exp.code.visit(this)
                super.transform(exp)
            } else {
                super.transform(exp)
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;find the method which will eventually be called, &lt;code&gt;methodMissing&lt;/code&gt; and keep a handle on it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;when an expression is visited, we check if it is a method call which should be replaced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;create a new method call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;link the call to its target method (very important if you don&amp;#8217;t want to crash the compiler!)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;return the new method call&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And we&amp;#8217;re done! Of course, I didn&amp;#8217;t say it was trivial nor easy, yet, it is possible, and now, all methods supposed to create a tag are directly wired to &lt;code&gt;methodMissing&lt;/code&gt;, meaning that they are now statically compiled!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_more_things_to_fix&quot;&gt;More things to fix&amp;#8230;&amp;#8203;&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You may think that all problems are solved, but in fact, there are still issues with this code. Imagine the following template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(text.toUpperCase())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you compile it, it will fail with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is right and if the method exists.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The reason is that we compile the template statically. While we instructed the compiler that &lt;code&gt;text&lt;/code&gt; is in fact &lt;code&gt;getModel().get(&quot;text&quot;)&lt;/code&gt;, it is still unable to know what is the return type of this call. Then, it assumes that it returns an &lt;code&gt;Object&lt;/code&gt;, and if you try to call &lt;code&gt;toUpperCase&lt;/code&gt; on an &lt;code&gt;Object&lt;/code&gt;, the method doesn&amp;#8217;t exist&amp;#8230;&amp;#8203; This can easily be solved, by making all unresolved method calls dynamic. This means that the template compilation will never throw such errors anymore, but it will instead make a dynamic call. Problem solved.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, almost.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What if I do this?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(((String)text).toUpperCase())&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then, by adding a cast, the static compiler is able to resolve the method call. Instead of doing a dynamic call, like it would with our extension, it will perform a direct method call, which will be faster! This means that if you add types, by casting, to your template, rendering can be made faster.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is an interesting idea, but it is not really user friendly. So the last thing I added to the type checking extension is actually an optional, &quot;type checked&quot; mode. If this mode is activated, then the programmer is supposed to tell which are the types of the elements found into the binding. Here, the developper would have to declare that &lt;code&gt;text&lt;/code&gt; is of type String:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

def tplConf = new TemplateConfiguration()
MarkupTemplateEngine engine = new MarkupTemplateEngine(this.class.classLoader, tplConf)

def mkpTemplate = engine.createTypeCheckedModelTemplate &apos;&apos;&apos;				&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
p {
   yield text.toUpperCase()								&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
}
&apos;&apos;&apos;, [text:&apos;String&apos;]
def model = [text:&apos;Text &amp;lt;to be escaped&amp;gt;&apos;]						&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
mkpTemplate.make(model).writeTo(new PrintWriter(System.out))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;use &lt;code&gt;createTypeCheckedModelTemplate&lt;/code&gt; instead of &lt;code&gt;createTemplate&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;you can use &lt;code&gt;text.toUpperCase()&lt;/code&gt; without an explicit cast&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;because the model was declared using a simple map&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This mode is actually very interesting if you want to report template errors at &lt;em&gt;template compilation&lt;/em&gt; time. Instead of having an error when the template is rendered, the error will occur at compile time. So, for example, if we change the model declaration from:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;[text:&apos;String&apos;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;[text:&apos;Integer&apos;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;template compilation will now fail with:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[Static type checking] - Cannot find matching method java.lang.Integer#toUpperCase(). Please check if the declared type is right and if the method exists.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is really interesting is that you can declare &quot;complex&quot; models, like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;[persons:&apos;List&amp;lt;Person&amp;gt;&apos;, posts:[List&amp;lt;Post&amp;gt;]]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and have the template statically compiled! The implementation details of that mode are a bit complex, but you can take a look at the &lt;a href=&quot;https://github.com/melix/groovy-core/commit/30096837f8494d64d249a3341efca7ea66bb816f&quot;&gt;commit&lt;/a&gt; if you want to have some hint (don&amp;#8217;t hesitate to ask me if you want me to explain how it works).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_and_more_features&quot;&gt;And more features!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, the template engine implements automatic indent and automatic new lines. The first one is quite easy to implement, as it only requires wrapping the supplied &lt;code&gt;Writer&lt;/code&gt; into an &lt;code&gt;IndentWriter&lt;/code&gt;. But adding automatic new lines is a bit trickier, because we want to rely on the layout of the source code to actually add behavior! Let me explain that again with examples. If you have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;div {
  p(&apos;text&apos;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;we want to render:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;div&amp;gt;
    &amp;lt;p&amp;gt;Text&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But if we have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;div {  p(&apos;text&apos;) }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We want to render:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;div&amp;gt;&amp;lt;p&amp;gt;Text&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem is that our templates are actually Groovy code&amp;#8230;&amp;#8203; And new lines are not significant. They are not even visible in the AST, so how can we implement such a feature?! The answer relies in each AST node&amp;#8230;&amp;#8203; They all carry line and column number information. So, by comparing, in a &lt;code&gt;ClosureExpression&lt;/code&gt;, the line number of the closure itself with the line number of its first code statement, we can determine if there was a new line in source code! The same way, we can check if the last line number of the closure is greater than the line number of the last statement, and if so, introduce a new line&amp;#8230;&amp;#8203; So, in the first example, the code is actually transformed into:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;div {
  newLine()
  p(&apos;text&apos;)
  newLine()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And that&amp;#8217;s it!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this (long) blog post, I have demonstrated various techniques that allowed me to transform a slow, dynamic builder based template engine into a fast, statically compiled, template engine with optional user model type checking and unique features like automatic new line insertions. It goes far beyond what the &lt;code&gt;StreamingMarkupBuilder&lt;/code&gt; has to offer and demonstrates that compile time metaprogramming can be used in Groovy to provide advanced features. Of course, no one would expect you to create such code from the beginning. If you &lt;a href=&quot;https://github.com/melix/groovy-core/commits/markup-template-engine&quot;&gt;take a look at the branch commits&lt;/a&gt;, you will definitely see that I went step by step. And eventually, I will issue a pull request when I think that the code is ready for prime time. I am not sure yet this should make into core groovy, or instead if it should go into an external project. Ideas are welcome!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I still have to make some changes, like not reporting errors if the type checking mode is not active (and always going through dynamic mode in that case) and probably write more benchmarks, but I&amp;#8217;m really looking forward to read what you think. Oh yes, one last thing: congratulations if you read that post throughfully!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A fast markup template engine for Groovy (part 1 of 2)</title>
      <link>https://melix.github.io/blog//2014/02/markuptemplateengine.html</link>
      <pubDate>Sun, 16 Feb 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/02/markuptemplateengine.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Recently, I was &lt;a href=&quot;https://twitter.com/CedricChampeau/status/431131840788041728&quot;&gt;surprised&lt;/a&gt; no-one had the idea of developping a template engine relying on the Groovy &lt;a href=&quot;https://groovy.codehaus.org/Creating+XML+using+Groovy&amp;#8217;s+MarkupBuilder&quot;&gt;MarkupBuilder&lt;/a&gt;. Working on &lt;a href=&quot;https://jbake.org/&quot;&gt;JBake&lt;/a&gt; made me take a look at existing template engines for Java again, something I hadn&amp;#8217;t done for years, and even if new technologies like &lt;a href=&quot;https://www.thymeleaf.org/&quot;&gt;Thymeleaf&lt;/a&gt; or &lt;a href=&quot;https://jknack.github.io/handlebars.java/gettingStarted.html&quot;&gt;Handlebars&lt;/a&gt; exist, not of them are as practical to use as the markup builder.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_an_interesting_experiment&quot;&gt;An interesting experiment&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For that reason, I started working on a new template engine leveraging Groovy. The primary focus of this template engine would be XML-like markup (XHTML, HTML5, XML, &amp;#8230;&amp;#8203;), but in theory, it can be used to render anything. The basic idea is that you can write a template which looks like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
    body {
        yield message			&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&apos;message&apos; is a template variable&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which renders to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It works!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My first implementation was done quickly done and was leveraging the &lt;a href=&quot;https://groovy.codehaus.org/gapi/groovy/xml/StreamingMarkupBuilder.html&quot;&gt;StreamingMarkupBuilder&lt;/a&gt;. It wasn&amp;#8217;t very difficult to write, but it had a problem: in general, builders are quite slow, so not very suitable for templating engines, where you should render a page as fast as possible. To check this, I wrote a simple micro-benchmark, which compared my template engine with Freemarker:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@Grab(group=&apos;org.gperfutils&apos;, module=&apos;gbench&apos;, version=&apos;0.4.2-groovy-2.1&apos;)
@Grab(&apos;org.freemarker:freemarker:2.3.9&apos;)
import groovy.text.markup.MarkupTemplateEngine
import freemarker.template.*

MarkupTemplateEngine engine = new MarkupTemplateEngine()
def mkpTemplate1 = engine.createTemplate &apos;&apos;&apos;
html {
    body(&apos;It works!&apos;)
}
&apos;&apos;&apos;
def mkpTemplate2 = engine.createTemplate &apos;&apos;&apos;
html {
    body(text)
}
&apos;&apos;&apos;

def mkpTemplate3 = engine.createTemplate &apos;&apos;&apos;
html {
    body(text.toUpperCase())
}
&apos;&apos;&apos;

def cfg = new Configuration()
def ftlTemplate1 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It works!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def ftlTemplate2 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;${text}&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def ftlTemplate3 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;${text?upper_case}&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def r = benchmark {
    &apos;MarkupTemplateEngine (simple, no binding)&apos; { mkpTemplate1.make([:]).writeTo(new StringWriter()) }
    &apos;Freemarker (simple, no binding)&apos; { ftlTemplate1.process([:], new StringWriter()) }
    &apos;MarkupTemplateEngine (simple binding)&apos; { mkpTemplate2.make([text:&apos;Hello&apos;]).writeTo(new StringWriter()) }
    &apos;Freemarker (simple binding)&apos; { ftlTemplate2.process([text:&apos;Hello&apos;], new StringWriter()) }
    &apos;MarkupTemplateEngine (simple toUpper)&apos; { mkpTemplate3.make([text:&apos;Hello&apos;]).writeTo(new StringWriter()) }
    &apos;Freemarker (simple toUpper)&apos; { ftlTemplate3.process([text:&apos;Hello&apos;], new StringWriter()) }
}

r.prettyPrint()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I expected my template engine to be slower, yet I didn&amp;#8217;t expect it to be &lt;strong&gt;that&lt;/strong&gt; slow:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;                                            user  system    cpu   real

MarkupTemplateEngine (simple, no binding)  23038       0  23038  23059
Freemarker (simple, no binding)              385       0    385    392
MarkupTemplateEngine (simple binding)      26221       0  26221  26244
Freemarker (simple binding)                 1037       1   1038   1046
MarkupTemplateEngine (simple toUpper)      26895       0  26895  26929
Freemarker (simple toUpper)                 1161       0   1161   1171&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As wisdom says, make it work, make it right, then make it fast. I already had it working and it did what I wanted, so the next logical step would therefore be optimizing&amp;#8230;&amp;#8203; But before I show you the results of that steps, let&amp;#8217;s take a look at the features I have implemented so far.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_features&quot;&gt;Features&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am quite happy with the current feature set, which I think is good enough for a public review. Here is a quick list.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_builder_syntax&quot;&gt;builder syntax&lt;/h3&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;html {
   head {
      meta(charset:&apos;utf-8&apos;)
      title(&apos;Page title&apos;)
   }
}&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta charset=&quot;utf-8&quot;&amp;gt;&amp;lt;title&amp;gt;Page title&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For that, the code to initialize the template engine is quite simple (note that you can use it in Java too):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration

def tplConf = new TemplateConfiguration()
MarkupTemplateEngine engine = new MarkupTemplateEngine(this.class.classLoader, tplConf)

def mkpTemplate1 = engine.createTemplate &apos;&apos;&apos;
html {
   head {
      meta(charset:&apos;utf-8&apos;)
      title(&apos;Page title&apos;)
   }
}
&apos;&apos;&apos;

def model = [:]

mkpTemplate1.make(model).writeTo(new PrintWriter(System.out))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_groovy_goodness&quot;&gt;Groovy goodness&lt;/h3&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;ul {
   persons.each { p -&amp;gt;
   	li(p.name)
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the following model:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def model = [persons: [new Person(name:&apos;Bob&apos;), new Person(name:&apos;Alice&apos;)]]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Renders to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;Bob&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;Alice&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_template_inclusion&quot;&gt;template inclusion&lt;/h3&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_inclusion_of_another_template&quot;&gt;inclusion of another template&lt;/h4&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   include template: &apos;includes/header.tpl&apos;
   include template: &apos;includes/body.tpl&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_inclusion_of_escaped_text&quot;&gt;inclusion of escaped text&lt;/h4&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   div(class:&apos;post&apos;) {
   	include escaped: &apos;content/text.txt&apos;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_inclusion_of_unescaped_text&quot;&gt;inclusion of unescaped text&lt;/h4&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   div(class:&apos;post&apos;) {
   	include unescaped: &apos;content/raw.txt&apos;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_automatic_escaping_of_user_input&quot;&gt;automatic escaping of user input&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, variables read from the model will be escaped. For example, given the following model:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def model = [text:&apos;&amp;lt;html&amp;gt;&apos;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and the following template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(text)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the result will be:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;&amp;lt;p&amp;gt;&amp;amp;lt;html&amp;amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It is possible to avoid escaping by prefixing the variable name with &lt;code&gt;unescaped.&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;p(unescaped.text)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_automatic_indentation&quot;&gt;automatic indentation&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Automatic indentation allows the programmer to get rid of indent instructions. For the following template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   newLine()
   body {
newLine()
p(&apos;Auto indent in action!&apos;)
newLine()
   }
   newLine()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The result without automatic indent is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;p&amp;gt;Auto indent in action!&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If auto-indent is activated, then the output is changed to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;p&amp;gt;Auto indent in action!&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_automatic_new_lines&quot;&gt;automatic new lines&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The previous example was nice, but you have a lot of &lt;code&gt;newLine&lt;/code&gt; method calls. Activating auto-newline will use the open blocks to introduce newLines automatically. That means that you can change the template to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {
   body {
p(&apos;Auto indent in action!&apos;)
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which is much more readable! To understand how it works, let&amp;#8217;s slightly change the template, by moving the &lt;code&gt;body&lt;/code&gt; block to the same line as &lt;code&gt;html&lt;/code&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;html {   body {
p(&apos;Auto indent in action!&apos;)
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;in that case, the output is modified accordingly:
-&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;
        &amp;lt;p&amp;gt;Auto indent in action!&amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that new lines are really added where you have them in source code!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_optional_type_checking_of_model&quot;&gt;optional type checking of model&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine the following model:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class User {
   Long id
   String name
}

def model = [user: new User(id: 123, name: &apos;Cedric&apos;)]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and the following code to create a template:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def template = engine.createTemplate &apos;&apos;&apos;
p &quot;User id: $user.id Name: $user.name Age: $user.age&quot;
&apos;&apos;&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The template is compiled fine, but if you try to render it, it will fail:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;template.make(model).writeTo(new PrintWriter(System.out)) 	&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;fails with groovy.lang.MissingPropertyException: No such property: age for class: User&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To avoid failing at render time, you can use a type checked mode:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def template = engine.createTypeCheckedModelTemplate &apos;&apos;&apos;	&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
p &quot;User id: $user.id Name: $user.name Age: $user.age&quot;
&apos;&apos;&apos;, [user: &apos;User&apos;]						&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;use &lt;em&gt;createTypeCheckedModelTemplate&lt;/em&gt; instead of &lt;em&gt;createTemplate&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;provide model type information&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And this time, compilation of the template will fail directly:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[Static type checking] - No such property: age for class: User&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that it won&amp;#8217;t wait for an actual template to be rendered for failing, which is a feature some people like (yes, I&amp;#8217;m looking at you, Play! Framework ;)). Now that we&amp;#8217;ve showed a quick list of those features (there are more, like helper methods in model, &amp;#8230;&amp;#8203;), what about performance? Is it worth it? I thought Groovy, and builders, were slow?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_statically_compiled_templates&quot;&gt;Statically compiled templates&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had already played with &lt;a href=&quot;/blog/2013/02/13/static_builders_inception.html&quot;&gt;static builders&lt;/a&gt; in the past, and we also have this very nice feature of static type checking extensions in Groovy 2.1. In Groovy 2.2, type checking extensions were extended to static compilation&amp;#8230;&amp;#8203; So my first idea was to get rid of the &lt;code&gt;StreamingMarkupBuilder&lt;/code&gt;, which is good but not really suited for optimizations. And before I explain the implementation details, here is the result of a more complete benchmark, using my latest implementation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;@Grab(group=&apos;org.gperfutils&apos;, module=&apos;gbench&apos;, version=&apos;0.4.2-groovy-2.1&apos;)
@Grab(&apos;org.freemarker:freemarker:2.3.9&apos;)
import groovy.text.markup.MarkupTemplateEngine
import freemarker.template.*

MarkupTemplateEngine engine = new MarkupTemplateEngine()
def mkpTemplate1 = engine.createTemplate &apos;&apos;&apos;
html {
    body(&apos;It works!&apos;)
}
&apos;&apos;&apos;
def mkpTemplate2 = engine.createTemplate &apos;&apos;&apos;
html {
    body(text)
}
&apos;&apos;&apos;

def mkpTemplate3 = engine.createTemplate &apos;&apos;&apos;
html {
    body(text.toUpperCase())
}
&apos;&apos;&apos;

def mkpTemplate3_typed = engine.createTemplate &apos;&apos;&apos;
html {
    body(((String)text).toUpperCase())
}
&apos;&apos;&apos;

def mkpTemplate4 = engine.createTemplate &apos;&apos;&apos;
html {
    body {
        ul {
            persons.each {
                li(&quot;$text $it&quot;)
            }
        }
    }
}
&apos;&apos;&apos;

def mkpTemplate4_typed = engine.createTemplate &apos;&apos;&apos;
List&amp;lt;String&amp;gt; pList = (List&amp;lt;String&amp;gt;) persons
String txt = text
html {
    body {
        ul {
            for (String p: pList) {
                li(&quot;$txt $p&quot;)
            }
        }
    }
}
&apos;&apos;&apos;

def model = [text:&apos;Hello&apos;, persons:[&apos;Cedric&apos;,&apos;Guillaume&apos;,&apos;Jochen&apos;,&apos;Pascal&apos;,&apos;Paul&apos;]]

def cfg = new Configuration()
def ftlTemplate1 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It works!&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def ftlTemplate2 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;${text}&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def ftlTemplate3 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;${text?upper_case}&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);
def ftlTemplate4 = new Template(&quot;name&quot;, new StringReader(&apos;&apos;&apos;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;#list persons as person&amp;gt;&amp;lt;li&amp;gt;${text} ${person}&amp;lt;/#list&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&apos;&apos;&apos;), cfg);

def r = benchmark {
    &apos;MarkupTemplateEngine (simple, no binding)&apos; { mkpTemplate1.make([:]).writeTo(new StringWriter()) }
    &apos;Freemarker (simple, no binding)&apos; { ftlTemplate1.process([:], new StringWriter()) }
    &apos;MarkupTemplateEngine (simple binding)&apos; { mkpTemplate2.make(model).writeTo(new StringWriter()) }
    &apos;Freemarker (simple binding)&apos; { ftlTemplate2.process(model, new StringWriter()) }
    &apos;MarkupTemplateEngine (simple toUpper)&apos; { mkpTemplate3.make(model).writeTo(new StringWriter()) }
    &apos;Freemarker (simple toUpper)&apos; { ftlTemplate3.process(model, new StringWriter()) }
    &apos;MarkupTemplateEngine (typed toUpper)&apos; { mkpTemplate3_typed.make(model).writeTo(new StringWriter()) }
    &apos;MarkupTemplateEngine loop&apos; { mkpTemplate4.make(model).writeTo(new StringWriter()) }
    &apos;MarkupTemplateEngine typed for loop&apos; { mkpTemplate4_typed.make(model).writeTo(new StringWriter()) }
    &apos;FreeMarker loop&apos; {  ftlTemplate4.process(model, new StringWriter()) }
}

r.prettyPrint()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;                                           user  system   cpu  real

MarkupTemplateEngine (simple, no binding)   609       0   609   615
Freemarker (simple, no binding)             400       0   400   410
MarkupTemplateEngine (simple binding)       628       3   631   631
Freemarker (simple binding)                 864       0   864   877
MarkupTemplateEngine (simple toUpper)       681       0   681   690
Freemarker (simple toUpper)                 972       0   972   986
MarkupTemplateEngine (typed toUpper)        696       3   699   706
MarkupTemplateEngine loop                  2927      12  2939  2949
MarkupTemplateEngine typed for loop        2579       0  2579  2615
FreeMarker loop                            2862       0  2862  2894&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, there is a &lt;strong&gt;huge&lt;/strong&gt; difference. For non trivial templates, the markup template engine is even faster than Freemarker! To acheive such performance, all templates are compiled into bytecode, but also make use of static compilation, type checking extensions, AST transformations, &amp;#8230;&amp;#8203;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the next part, I will describe the techniques I used to implement this engine. Meanwhile, let me know what you think of it. If you feel brave, you can test it by checking out the sources on my fork:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone -b markup-template-engine https://github.com/melix/groovy-core.git
./gradlew console	&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;will compile Groovy and open a Groovy console where you can test the template engine&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Update: In &lt;a href=&quot;/blog/2014/02/markuptemplateengine_part2.html&quot;&gt;the next part&lt;/a&gt;, we discuss the technical details.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Authoring your blog on GitHub with JBake and Gradle</title>
      <link>https://melix.github.io/blog//2014/02/hosting-jbake-github.html</link>
      <pubDate>Mon, 3 Feb 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/02/hosting-jbake-github.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A few weeks ago, I started this new blog and decided to host it on GitHub. I already explained
&lt;a href=&quot;/blog/2013/11/21/a_new_home.html&quot;&gt;how I migrated contents from JRoller&lt;/a&gt;, but I didn&amp;#8217;t really
the tool behind publishing. In this post, I will show you how easy it is, now that I have
improved my toolchain with &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_jbake&quot;&gt;JBake&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; is a static site generator. When I chose this tool for my blog,
what attracted me is actually that it runs on the JVM, so I already had the idea of automating
stuff with &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since then, I have submitted several pull requests to the project, and we&amp;#8217;re actually thinking
of using it to build the next Groovy website. &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; has good chances to
become the &quot;Jekyll of the JVM&quot; and already supports multiple markup languages (markdown, asciidoc)
as well as multiple template engines (&lt;a href=&quot;https://freemarker.org/&quot;&gt;FreeMarker&lt;/a&gt; in 2.2.1, &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt;
and &lt;a href=&quot;https://www.thymeleaf.org/&quot;&gt;Thymeleaf&lt;/a&gt; in 2.3.0).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea behind &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; is very simple: contents is written using a markup language and &quot;baked&quot;
with template engines into actual HTML. Everything is generated statically and you can upload the generated site
wherever you want.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On the other side, GitHub offers a nice tool to publish pages: &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;, so we can
have both the sources of our blog and the output of bakery in the same repository. So the initial process looked
like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;olist arabic&quot;&gt;
&lt;ol class=&quot;arabic&quot;&gt;
&lt;li&gt;
&lt;p&gt;create a new page in &lt;code&gt;content&lt;/code&gt; directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;run &lt;code&gt;jbake&lt;/code&gt; command, check the result, eventually make changes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git add page.adoc&lt;/code&gt; to add the new page to the sources&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git commit -a&lt;/code&gt; to commit the page to the &lt;code&gt;master&lt;/code&gt; branch, corresponding to the sources of the blog&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git checkout gh-pages&lt;/code&gt; to switch to the GitHub pages branch&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cp -R output/* .&lt;/code&gt; to copy the contents of the output directory at the root of the GitHub pages&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git add page.html&lt;/code&gt; to add the new page to the GitHub pages branch&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git commit -a&lt;/code&gt; to commit the contents to GitHub pages&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git push origin master&lt;/code&gt; to push the sources to GitHub&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;git push origin gh-pages&lt;/code&gt; to push the generated pages to GitHub pages&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I published my first blog posts like this, and it&amp;#8217;s not that complicated, but it involves a lot of manual steps, so I
came up with a Gradle plugin to make this much easier, that is, focusing on contents, period!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gradle_to_the_rescue&quot;&gt;Gradle to the rescue!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We&amp;#8217;re going to setup a project that will allow you to publish to GitHub pages in one step, using &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt;. For that,
we will need:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;an empty &lt;em&gt;blog&lt;/em&gt; repository that you created on GitHub&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; to setup the initial JBake project structure&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; 1.10 (previous versions should work too)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/jbake-org/jbake-gradle-plugin&quot;&gt;JBake plugin for Gradle&lt;/a&gt;, will be downloaded automatically&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/ajoberstar/gradle-git&quot;&gt;Git plugin for Gradle&lt;/a&gt;, will be downloaded automatically&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_building_jbake&quot;&gt;Building JBake&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This step will become optional when JBake 2.3.0 will be out (or a snapshot of &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; will be published). Meanwhile, you
need to install a local version of &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; into your local Maven repository. Don&amp;#8217;t worry, this will be easy, you will
only need Maven (hey, too bad &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; doesn&amp;#8217;t use Gradle ;)):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git clone https://github.com/jbake-org/jbake.git
cd jbake
mvn install&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That&amp;#8217;s all!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_setting_up_a_project&quot;&gt;Setting up a project&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First step consists in creating the initial project layout:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;git init                                                            &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
git remote add origin &amp;lt;your github remote url&amp;gt;                      &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
mkdir -p src/jbake                                                  &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
gradle init                                                         &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
git add build.gradle gradle gradlew gradlew.bat settings.gradle src &lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;(5)&lt;/b&gt;
cd src/jbake
jbake -i                                                            &lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;(6)&lt;/b&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;initializes the git repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;add your remote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we will put JBake sources into that directory&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;installs the Gradle wrapper into the repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;5&quot;&gt;&lt;/i&gt;&lt;b&gt;5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;adds Gradle wrapper and initial structure into Git&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;6&quot;&gt;&lt;/i&gt;&lt;b&gt;6&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;initializes the default JBake directory layout&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_using_gradle_to_render_pages&quot;&gt;Using Gradle to render pages&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this point, your &lt;code&gt;src/jbake&lt;/code&gt; directory contains the classic &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; folder contents:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;src
 |-- jbake
       |-- assets    : static assets (images, css, ...)
       |-- content   : blog posts, ...
       |-- templates : HTML templates (by default, uses FreeMarker)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Replace the contents of &lt;code&gt;build.gradle&lt;/code&gt; with the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;build.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;buildscript {
  repositories {
      mavenLocal() // needed to use the local JBake 2.3.0 build
      jcenter()
  }

  dependencies {
    classpath &apos;me.champeau.gradle:jbake-gradle-plugin:0.1-SNAPSHOT&apos; &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    classpath &apos;org.asciidoctor:asciidoctor-java-integration:0.1.4&apos;  &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;
    classpath &apos;org.freemarker:freemarker:2.3.19&apos;                    &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
  }
}

apply plugin: &apos;jbake&apos;                                               &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;import the JBake plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if you write pages using the Asciidoctor format, this is necessary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;if you use the Freemarker template engine, this is necessary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;then apply the plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By default, the plugin will look for JBake sources in &lt;code&gt;src/jbake&lt;/code&gt; and generate the site into &lt;code&gt;build/jbake&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_generating_the_output&quot;&gt;Generating the output&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that this is applied, you can generate the site by running the following command:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;./gradlew -i jbake&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;after the rendering step, you should now have a new directory:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;build
  |-- jbake&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;into which you will find the generated HTML contents. At this point, you could choose to upload those files
to an FTP server, for example, but since we want to host our pages on GitHub, we need to add some configuration
to our build.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_publishing_to_github_pages&quot;&gt;Publishing to GitHub Pages&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Create a new file named &lt;code&gt;publish.gradle&lt;/code&gt; with the following contents:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;title&quot;&gt;publish.gradle&lt;/div&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;buildscript {
  repositories {
      jcenter()
  }

  dependencies {
    classpath &apos;org.ajoberstar:gradle-git:0.6.3&apos;     &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
  }
}

apply plugin: &apos;github-pages&apos;                        &lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;(2)&lt;/b&gt;

githubPages {
  repoUri = &apos;git@github.com:youtname/blog.git&apos;      &lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;(3)&lt;/b&gt;
  pages {
     from(file(&apos;build/jbake&apos;)) {
     	into &apos;.&apos;                                    &lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;(4)&lt;/b&gt;
     }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;use the gradle-git plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;2&quot;&gt;&lt;/i&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;apply the plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;3&quot;&gt;&lt;/i&gt;&lt;b&gt;3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;configure your GitHub repository URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;4&quot;&gt;&lt;/i&gt;&lt;b&gt;4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;tells the plugin to upload the contents of the &lt;code&gt;build/jbake&lt;/code&gt; directory&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then modify the main &lt;code&gt;build.gradle&lt;/code&gt; file by adding the following task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;task publish(type: GradleBuild) {           &lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;(1)&lt;/b&gt;
    buildFile = &apos;publish.gradle&apos;
    tasks = [&apos;publishGhPages&apos;]
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;td&gt;&lt;i class=&quot;conum&quot; data-value=&quot;1&quot;&gt;&lt;/i&gt;&lt;b&gt;1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;we&amp;#8217;re using a separate, sub-build to avoid a classpath issue with JNA&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now if you do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;./gradlew publish&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Gradle will pick the contents of the &lt;code&gt;output/jbake&lt;/code&gt; directory, add it to the &lt;code&gt;gh-pages&lt;/code&gt; branch and push it to GitHub,
all in one step! A few seconds later, you should see the result on github.io!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One last thing: this configuration does &lt;strong&gt;not&lt;/strong&gt; add the sources to your git repository. It only deals with the output,
so you still need to add the source files, commit them and push them to GitHub. This is of course optional if you
don&amp;#8217;t want to publish the sources&amp;#8230;&amp;#8203; If you decide to make them public, then you can also use the git plugin to do it
automatically!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, we&amp;#8217;ve shown you how you can leverage &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; and &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; to publish a blog on GitHub. The setup is really
easy, so I hope more people will follow that way and contribute to Open Source too!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, this post has been published using the procedure described on this page, so I used &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; and &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; to blog
about how to publish a blog on &lt;a href=&quot;https://github.com/melix/blog&quot;&gt;GitHub&lt;/a&gt; using &lt;a href=&quot;https://www.jbake.org&quot;&gt;JBake&lt;/a&gt; and &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt;! Like my friend Andres Almiray
would say, that&amp;#8217;s a &lt;a href=&quot;https://twitter.com/aalmiray/status/429236158321950720&quot;&gt;toolception&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JLangDetect 0.4 released and moved to GitHub</title>
      <link>https://melix.github.io/blog//2014/01/jlangdetect-github.html</link>
      <pubDate>Wed, 22 Jan 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/01/jlangdetect-github.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_new_era&quot;&gt;A new era&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Back in 2011, I initiated a project called &lt;code&gt;JLangDetect&lt;/code&gt;, a language detection library for the JVM. At that time, I was working for
a company that made NLP tools and I started this as a pet project on my free time. I made it available as open source software and
people started to use it, so I was pretty happy at that time to see a project I initiated being actually used in production!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While I don&amp;#8217;t have the need for such a library now that I work on the Groovy language, some people are still using it. At the first
place, a friend of mine, Freddy Rabiller, took time to upgrade it. A new version has been released (0.4) and the project is now
available on &lt;a href=&quot;https://github.com/melix/jlangdetect&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A big thank to Freddy, who will probably take the lead of development on this project now!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Closure parameter type inference for Groovy</title>
      <link>https://melix.github.io/blog//2014/01/closure_param_inference.html</link>
      <pubDate>Tue, 7 Jan 2014 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2014/01/closure_param_inference.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let&amp;#8217;s start 2014 with a new blog post about a long standing request since we introduced static type checking in Groovy 2: closure parameter type inference.
Before we start, let me wish you a happy new year and a lot of open source contributions!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_type_checking_closure_parameter_types&quot;&gt;Type checking closure parameter types&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To illustrate the problem, let&amp;#8217;s start with this very simple, standard, Groovy code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;void test() {
    assert [&apos;foo&apos;,&apos;bar&apos;,&apos;baz&apos;].collect { it.toUpperCase() } == [&apos;FOO&apos;,&apos;BAR&apos;,&apos;BAZ&apos;]
}
test()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This code compiles and runs perfectly fine. Now if you want the &lt;em&gt;test&lt;/em&gt; method to be type safe, you can annotate it with &lt;em&gt;@TypeChecked&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.transform.TypeChecked

@TypeChecked
void test() {
    assert [&apos;foo&apos;,&apos;bar&apos;,&apos;baz&apos;].collect { it.toUpperCase() } == [&apos;FOO&apos;,&apos;BAR&apos;,&apos;BAZ&apos;]
}
test()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you compile this, you will notice that the compiler fails with an error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[Static type checking] - Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is right and if the method exists.
 at line: 5, column: 42&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Fixing this requires an explicit closure parameter type:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;import groovy.transform.TypeChecked

@TypeChecked
void test() {
    assert [&apos;foo&apos;,&apos;bar&apos;,&apos;baz&apos;].collect { String it -&amp;gt; it.toUpperCase() } == [&apos;FOO&apos;,&apos;BAR&apos;,&apos;BAZ&apos;]
}
test()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem comes from the &lt;em&gt;collect&lt;/em&gt; method, which accepts a &lt;code&gt;Closure&lt;/code&gt;. In Groovy, a &lt;code&gt;Closure&lt;/code&gt; is a block of code which may capture variables, but it is also
represented as an object of the class &lt;code&gt;Closure&lt;/code&gt;. This is a different concept from Java 8 lambdas, which have no &lt;em&gt;Lambda&lt;/em&gt; class, for example. A Java 8 lambda can
be considered as purely syntactic sugar, which is interpreted as an interface implementation at compile time, although a &lt;code&gt;Closure&lt;/code&gt; can be manipulated. To illustrate
this, let&amp;#8217;s compare the signatures of &lt;em&gt;collect&lt;/em&gt; (in Groovy) and &lt;code&gt;Map&lt;/code&gt; (in Java 8) which correspond to the same concept:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T,U&amp;gt; List&amp;lt;U&amp;gt; collect(List&amp;lt;T&amp;gt; source, Closure&amp;lt;U&amp;gt; closure) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;items of the source list are of type T and converted to type U using the closure&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;&amp;lt;R&amp;gt; Stream&amp;lt;R&amp;gt; map(Function&amp;lt;? super T, ? extends R&amp;gt; mapper); &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Function is an interface, the lambda expression will be converted into this target interface&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The Java 8 equivalent would therefore be:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;list.stream().map((it)-&amp;gt;it.toUpperCase()).collect(Collectors.toList()); &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;we&amp;#8217;re not using the smarter method reference notation here, to illustrate the concept&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, Java allows the same thing as Groovy but doesn&amp;#8217;t require an explicit type. The reason is that for Java, there&amp;#8217;s no ambiguity:
it makes use of &lt;em&gt;target typing&lt;/em&gt;. Since a lambda is targetting an interface, the type of the parameters can be inferred from the interface type.
In Groovy, we can&amp;#8217;t do this, because &lt;code&gt;Closure&lt;/code&gt; is not an interface. It is a class which can be manipulated. At this point, you may wonder why
we don&amp;#8217;t do the same as in Java, and there are several reasons:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;historical reason first, &lt;code&gt;Closure&lt;/code&gt; was one of the key features of the language, 10 years ago!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a single class, &lt;code&gt;Closure&lt;/code&gt;, is enough for &lt;strong&gt;all&lt;/strong&gt; usages of an open block. We don&amp;#8217;t need Function, Consumer, BiFunction, &amp;#8230;&amp;#8203; So we can dramatically
reduce the amount of &quot;design interfaces&quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;last but not least, &lt;em&gt;Closures&lt;/em&gt; support various delegation strategies. This is something Java (or even Scala) is totally unable to do. &lt;code&gt;Closure&lt;/code&gt; can
be &lt;em&gt;cloned&lt;/em&gt;, &lt;em&gt;curried&lt;/em&gt;, &lt;em&gt;trampolined&lt;/em&gt;, &amp;#8230;&amp;#8203; and it always returns an instance of another &lt;code&gt;Closure&lt;/code&gt;. This closure can change the delegate, which is the
key for nice builder like DSLs. The delegate is used whenever a method call in a closure doesn&amp;#8217;t have an explicit receiver. For example:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;mail {
   from &apos;austin.powers@groovy.baby&apos;
   to &apos;mini.me@evil.com&apos;
   subject &apos;Attention please!&apos;
   body &apos;...&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this DSL, the &lt;em&gt;from&lt;/em&gt;, &lt;em&gt;to&lt;/em&gt;, &lt;em&gt;subject&lt;/em&gt; and &lt;em&gt;body&lt;/em&gt; method calls are done on the &lt;em&gt;delegate&lt;/em&gt;. Being able to set the &lt;em&gt;delegate&lt;/em&gt; absolutely requires a
&lt;code&gt;Closure&lt;/code&gt; class. The implementation of the mail method may have something like:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class EmailSpecification {
    void from(String sender) { ... }
    void to(String to) { ... }
    void subject(String subject) { ... }
    void body(String body) { ... }
    void mail(Closure mail) {
       def mailSpec = mail.clone()
       mailSpec.delegate = this
       mailSpec()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem with this approach is that if the closure requires parameters, like in the &lt;em&gt;collect&lt;/em&gt; case, the Java type system, as well as the Groovy type
system (which is the same), isn&amp;#8217;t expressive enough to let you define them:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T,U&amp;gt; List&amp;lt;U&amp;gt; collect(List&amp;lt;T&amp;gt; source, Closure&amp;lt;U&amp;gt; closure) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We could like to say that Closure returns a U, but also that it consumes a T&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course the first option that was studied was defining lots of &lt;code&gt;Closure&lt;/code&gt; interfaces, corresponding to the various number of arguments (up to some arbitrary limit):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T,U&amp;gt; List&amp;lt;U&amp;gt; collect(List&amp;lt;T&amp;gt; source, Closure1&amp;lt;T,U&amp;gt; closure) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Closure1 is a kind of closure which accepts a single argument and returns a value&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While this works, it has several drawbacks:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it requires a lot of arbitrary, totally useless in a dynamic context, number of interfaces/classes to define closures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it doesn&amp;#8217;t solve the case of polymorphic closures&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_polymorphic_closures&quot;&gt;Polymorphic closures&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Polywhat? In Groovy, closures can be polymorphic. To illustrate the concept, let&amp;#8217;s take a look at a common method that iterates on map entries:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def map = [key1: &apos;value 1&apos;, key2: &apos;value2&apos;]
map.each { k,v -&amp;gt; println &quot;Key is $k, value is $v&quot; } &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
map.each { e -&amp;gt; println &quot;Key is ${e.key], value is ${e.value}&quot; } &lt;b class=&quot;conum&quot;&gt;(2)&lt;/b&gt;
map.each { println &quot;Key is ${it.key], value is ${it.value}&quot; } &lt;b class=&quot;conum&quot;&gt;(3)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;version where the map entry is automatically converted into a key and value arguments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;version where the closure takes a single, &lt;code&gt;Map.Entry&lt;/code&gt; argument&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;version with an implicit argument, it, is a &lt;code&gt;Map.Entry&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In all cases, it is always the &lt;strong&gt;same&lt;/strong&gt; method which is called, that is to say &lt;em&gt;each(Closure)&lt;/em&gt; on a &lt;code&gt;Map&lt;/code&gt;. The signature of this method is:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;K,V&amp;gt; each(Map&amp;lt;K,V&amp;gt; self, Closure&amp;lt;?&amp;gt; onEachEntry)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, the return type of the closure doesn&amp;#8217;t help here, and just reading that signature, you have absolutely no way to guess that the closure
will accept either a &lt;code&gt;Map.Entry&lt;/code&gt; or a pair of &lt;code&gt;K,V&lt;/code&gt;. Nor does the compiler. At best, your IDE knows it, and it does because it is hardcoded! This is
exactly why the compiler fails, and also why so many people think it&amp;#8217;s &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY-5924&quot;&gt;a bug&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Not convinced? Let&amp;#8217;s make the same signature more cryptic:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;Dead,Pool&amp;gt; magneto(Map&amp;lt;Dead,Pool&amp;gt; self, Closure&amp;lt;?&amp;gt; professorX)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now can you guess what &lt;em&gt;professorX&lt;/em&gt; accepts as parameters? ;)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_tweaking_the_type_system&quot;&gt;Tweaking the type system&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We have discussed several options and we took the time to think about it, and after the last Groovy DevCon, which took place just before the
&lt;a href=&quot;https://skillsmatter.com/event-details/home/groovy-grails-exchange-2013&quot;&gt;Groovy and Grails eXchange 2013&lt;/a&gt; in London, I decided to work on an implementation.
For Groovy 2.1, we had introduced &lt;em&gt;@DelegatesTo&lt;/em&gt; for closures, to be able to help the compiler in the case we described above (hinting at the delegate type)
but we were still missing parameter type inference. My guess was that it was possible to do something similar to what &lt;em&gt;@DelegatesTo&lt;/em&gt; does, but for parameter
types.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_annotating_closures&quot;&gt;Annotating closures&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea is to annotate closures so that the compiler can fetch the information and infer the argument types from the context. In the case of a simple method
accepting a closure, a simple annotation could do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;void doSomething(String src, @ClosureParams(String.class) Closure cl) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;em&gt;@ClosureParams&lt;/em&gt; annotation is here to instruct the compiler that the closure will accept either an &lt;em&gt;implicit&lt;/em&gt; or &lt;em&gt;explicit&lt;/em&gt; parameter of type &lt;em&gt;String&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;doSomething {
   it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When the compiler determines that the method which will be called is &lt;em&gt;doSomething&lt;/em&gt; (remember that this is only possible if type checking is activated), then an
additional lookup on the &lt;em&gt;doSomething&lt;/em&gt; signature can be done, and we can retrieve the list of expected parameter types from the closure annotation. Success!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, not really:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;we still don&amp;#8217;t support polymorphic closures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;generics, GENERICS, aaahhhh, GENERICS!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_introducing_generics&quot;&gt;Introducing&amp;#8230;&amp;#8203; generics!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To make things a bit more complicated, we have generics. Don&amp;#8217;t get me wrong. From a user perspective, generics are very good because they make the code more readable
and help reduce the amount of boilerplate (think of vectors/maps before Java 1.5&amp;#8230;&amp;#8203;). The typical case is the &lt;em&gt;collect&lt;/em&gt; example that we used initially:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T,U&amp;gt; List&amp;lt;U&amp;gt; collect(List&amp;lt;T&amp;gt; source, Closure&amp;lt;U&amp;gt; closure) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, we want to say that the closure:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;is monomorphic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;accepts a single parameter of type T&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and the problem is&amp;#8230;&amp;#8203; how to express this? One might think that you could write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T,U&amp;gt; List&amp;lt;U&amp;gt; collect(List&amp;lt;T&amp;gt; source, @ClosureParams(T) Closure&amp;lt;U&amp;gt; closure) &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;but the truth is that the JVM doesn&amp;#8217;t support placeholders as annotation values, nor does it support parametrized types (like &lt;code&gt;@Foo(List&amp;lt;T&amp;gt;&lt;/code&gt;)). This tells us that the simple strategy doesn&amp;#8217;t work.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_solution&quot;&gt;The solution&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The solution we propose is to decouple the declaration of the parameter types from the type itself. In other words, instead of declaring the types in the annotation, we will declare an object
which is used as a hint to compute the types &lt;strong&gt;at compile time&lt;/strong&gt;. In the case of &lt;em&gt;collect&lt;/em&gt;, we end up with this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static &amp;lt;T,E&amp;gt; List&amp;lt;T&amp;gt; collect(List&amp;lt;E&amp;gt; self, @ClosureParams(FirstParam.FirstGenericType.class) Closure&amp;lt;? extends T&amp;gt; transform)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, &lt;code&gt;FirstParam.FirstGenericType&lt;/code&gt; doesn&amp;#8217;t represent the type itself. It&amp;#8217;s a hint used by the compiler, which says &quot;the type of the argument is the type of the first generic type of the first parameter&quot;. In this case, the first parameter is &lt;code&gt;List&amp;lt;E&amp;gt;&lt;/code&gt;, so the first generic type is &lt;code&gt;E&lt;/code&gt;. This means that if you call the method with a &lt;code&gt;List&amp;lt;String&amp;gt;&lt;/code&gt;, now the compiler can infer that &lt;code&gt;E&lt;/code&gt; is a &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_type_hints&quot;&gt;Type hints&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At this point, you may actually think that this &quot;solution&quot; is a bit complex. However, you have to remember that this kind of work is only necessary if you want to support type inference, so it is really only necessary if you use type checking. This makes this a tool primarily aimed at framework builders. In particular, lots of frameworks are written in Java (including Groovy itself), so the syntax &lt;strong&gt;has&lt;/strong&gt; to be compatible with Java. Second, there&amp;#8217;s no need to define one &lt;code&gt;FirstParam.FirstGenericType&lt;/code&gt; class per method. The same class can be reused for all cases where it makes sense. Remember that it doesn&amp;#8217;t represent the type of the parameters but a way to fetch the type (one level of indirection).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To make things easier for framework writers, the &lt;a href=&quot;https://github.com/groovy/groovy-core/pull/307&quot;&gt;candidate implementation&lt;/a&gt; provides a set of predefined hint classes that should fit most of
the use cases. Let&amp;#8217;s go through the list:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_firstparam&quot;&gt;FirstParam&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;FirstParam&lt;/code&gt; is a hint that says that the expected parameter type corresponds to the first parameter of the method call, like in:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static void downto(BigInteger self, Number to, @ClosureParams(FirstParam.class) Closure closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The closure accepts a single parameter of type &lt;code&gt;BigInteger&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_firstparam_firstgenerictype&quot;&gt;FirstParam.FirstGenericType&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This hint is used when the type to use is not the type of the parameter, but the type of the first generic type of the first argument, like in:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static &amp;lt;T,E&amp;gt; Collection&amp;lt;T&amp;gt; collect(Collection&amp;lt;E&amp;gt; self, Collection&amp;lt;T&amp;gt; collector, @ClosureParams(FirstParam.FirstGenericType.class) Closure&amp;lt;? extends T&amp;gt; transform)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that if you have a &lt;code&gt;Collection&lt;/code&gt; defined like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class PersonList extends LinkedList&amp;lt;Person&amp;gt; {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and that you call collect:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;list.collect { it.name }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;the compiler will be capable of inferring that the type of the first generic type is actually a &lt;code&gt;Person&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;code&gt;FirstParam&lt;/code&gt; also supports &lt;code&gt;SecondGenericType&lt;/code&gt; and &lt;code&gt;ThirdGenericType&lt;/code&gt;. You can also find &lt;code&gt;SecondParam&lt;/code&gt; and &lt;code&gt;ThirdParam&lt;/code&gt; which follow the same structure.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_mapentryorkeyvalue&quot;&gt;MapEntryOrKeyValue&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This hint is used for cases where the closure may accept a &lt;code&gt;Map.Entry&lt;/code&gt; or a &lt;em&gt;key,value&lt;/em&gt; pair, which is quite common in the Groovy GDK, like &lt;em&gt;each&lt;/em&gt; on maps:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static &amp;lt;K, V&amp;gt; Map&amp;lt;K, V&amp;gt; each(Map&amp;lt;K, V&amp;gt; self, @ClosureParams(MapEntryOrKeyValue.class) Closure closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It is an example of polymorphic closure. This hint does all the job of telling that the parameter types may be a &lt;code&gt;K,V&lt;/code&gt; pair or a &lt;code&gt;Map.Entry&amp;lt;K,V&amp;gt;&lt;/code&gt;. For that, it expects the map to be the first parameter of the method.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_simpletype&quot;&gt;SimpleType&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Simple type can be used for monomorphic closures, in the cases the closure accepts parameters of a non-parametrized type. In this case, you need to use an option to specify the fully qualified name, like in this example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static void eachByte(InputStream is, @ClosureParams(value=SimpleType.class, options=&quot;byte&quot;) Closure closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this example, the closure accepts a single parameter of type &lt;code&gt;byte&lt;/code&gt;. For a non primitive type, you need the fully qualified name:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static Writable filterLine(InputStream self, @ClosureParams(value=SimpleType.class, options=&quot;java.lang.String&quot;) Closure predicate)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If the closure accepts multiple arguments then you need options to be an array:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static &amp;lt;T&amp;gt; T withObjectStreams(Socket socket, @ClosureParams(value=SimpleType.class, options={&quot;java.io.ObjectInputStream&quot;,&quot;java.io.ObjectOutputStream&quot;}) Closure&amp;lt;T&amp;gt; closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_fromstring&quot;&gt;FromString&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last predefined hint can be used whenever none of the previous hints is suitable. A good example is the &lt;em&gt;sort&lt;/em&gt; method on a collection, which takes a closure which either accepts a single
parameter of type &lt;code&gt;T&lt;/code&gt; (where &lt;code&gt;T&lt;/code&gt; is the component type) or two parameters of type &lt;code&gt;T&lt;/code&gt; in which case we have a comparator-style closure:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; sort(Collection&amp;lt;T&amp;gt; self, @ClosureParams(value=FromString.class, options={&quot;T&quot;,&quot;T,T&quot;} Closure c)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As you can see, in this example, the &lt;em&gt;options&lt;/em&gt; map defines two possible signatures. The string literal are used at compile time to match those of the method signature. Since it involves much more work for the compiler, it is not recommanded to use &lt;code&gt;FromString&lt;/code&gt; if other options are available, because it would be slower at compile time.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_future_work&quot;&gt;Future work&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The candidate implementation is available on &lt;a href=&quot;https://github.com/groovy/groovy-core/pull/307&quot;&gt;GitHub&lt;/a&gt;. It works pretty well, and honestly, I couldn&amp;#8217;t come with any better idea. One very good point of this implementation is that it is Java friendly. You can annotate classes written in pure Java and the Groovy compiler would be able to use the extra information. In the future, we could probably support a nicer syntax for Groovy, but it would require a grammar change, which is not planned until Groovy 3. For example, we could write this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;public static &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; sort(Collection&amp;lt;T&amp;gt; self, Closure&amp;lt;T or T,T -&amp;gt; ?&amp;gt; c)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Which would totally avoid the &quot;ugliness&quot; of the annotation, while using the same backing tool.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last thing, do not hesitate to comment on this blog about the solution we found. Of course, it took some time, and the discussions can be found here:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://groovy.329449.n5.nabble.com/TypeChecked-type-inference-does-not-work-with-closure-td5709972.html#a5709981&quot;&gt;an example of user complaint&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://groovy.329449.n5.nabble.com/Closure-parameter-types-inference-td4978037.html&quot;&gt;Initial, not satisfying, solution, two years ago&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://groovy.329449.n5.nabble.com/Closure-parameter-type-inference-td5717804.html&quot;&gt;discussion about this solution&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Thanks to everybody who participated in the discussion, and, of course, thank you for your comments if any: this is still a &lt;em&gt;candidate&lt;/em&gt; solution, so if you come with any better idea, I&amp;#8217;m open!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Performance of coercion vs closures in Groovy 2.2</title>
      <link>https://melix.github.io/blog//2013/11/22/coercion_vs_direct.html</link>
      <pubDate>Fri, 22 Nov 2013 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2013/11/22/coercion_vs_direct.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To inaugurate this new blog, I will discuss the topic of coercion performance in Groovy. Especially, you might now
that Groovy 2.2 &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Groovy+2.2+release+notes&quot;&gt;introduced implicit closure coercion&lt;/a&gt;.
If you don&amp;#8217;t know what closure coercion is, or just what &lt;em&gt;coercion&lt;/em&gt; alone is, let&amp;#8217;s start with a reminder.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_casting_vs_coercion&quot;&gt;Casting vs coercion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_casting&quot;&gt;Casting&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In an object oriented language like &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt;, variables are typed. Even if Groovy is a dynamic
language, each variable has a type at runtime. Even if Groovy shares the same typing model as Java, there&amp;#8217;s almost no
need for casting in Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Casting in Java is necessary because it&amp;#8217;s a statically typed language, so if you want to call a method defined on the
&lt;code&gt;Person&lt;/code&gt; class on an object which is declared as type &lt;code&gt;Object&lt;/code&gt;, you &lt;strong&gt;have&lt;/strong&gt; to do a cast:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;String pretty(Object o) {
    if (o instanceof Person) {
	return ((Person)o).getName(); // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;(Person) is an explicit cast&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;in Groovy, casting is not necessary because we rely on runtime types and dynamic invocation. This means that this code is
equivalent to this in Groovy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;String pretty(o) {
    o.name // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;casting isn&amp;#8217;t required&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Casting is only possible within the type hierarchy. That is, you can cast any object to any subtype (or interface) and it&amp;#8217;s
you&amp;#8217;re responsability to make sure (for example using &lt;code&gt;instanceof&lt;/code&gt;) that the runtime type will be correct. If you don&amp;#8217;t, you
may have the famous &lt;code&gt;ClassCastException&lt;/code&gt; error at runtime.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_coercion&quot;&gt;Coercion&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For types which are not in the same hierarchy, Groovy provides an alternative mechanism called &lt;em&gt;coercion&lt;/em&gt;. Coercion is very
handy because it basically allows you to convert an object of some type into an object of another, in general incompatible, type.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A good example is converting a &lt;code&gt;File&lt;/code&gt; to a &lt;code&gt;String[]&lt;/code&gt; corresponding to the lines of a text file. In groovy, you can write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def lines = file as String[]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Obviously, if you had written:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def lines = (String[]) file&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then it would have produced a &lt;code&gt;ClassCastException&lt;/code&gt;. Basically, a cast is (almost) a no-op, while coercion involves any kind of
treatment. It is also possible to implement your own coercion rules, by implementing the &lt;code&gt;asType&lt;/code&gt; method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;class Person {
   String name
   int age
   def asType(Class target) {
      if (List==target) {
         [name,age]
      }
   }
}
def p = new Person(name:&apos;Austin Powers&apos;, age:50)
assert p as List == [&apos;Austin Powers&apos;, 50]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_closure_coercion&quot;&gt;Closure coercion&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the most widely used features of Groovy is closure coercion. It&amp;#8217;s an easy way to implement interfaces. For example, giving
the following interface:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;interface Predicate {
    boolean apply(Object target)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can implement it using coercion:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;Predicate filter = { it.length() &amp;gt; 3 } as Predicate&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is especially interesting when the interface is used as a method call parameter:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;List filter(List source, Predicate predicate) {
   source.findAll { predicate.apply(it) } // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;note that this example doesn&amp;#8217;t really make sense since it&amp;#8217;s the role of findAll to apply a closure as predicate!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So you can call the method without having to create an anonymous abstract class:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def items = filter([&apos;foo&apos;,&apos;bar&apos;, &apos;foobar&apos;], {
    it.length()&amp;gt;3
} as Predicate)
assert items == [&apos;foobar&apos;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_implicit_closure_coercion_in_groovy_2_2&quot;&gt;Implicit closure coercion in Groovy 2.2&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With the release of Groovy 2.2, closure coercion can be implicit, in case the target is a SAM (single abstract method) type. That is to say that the target type must have a single abstract method, which is the case for many functional interfaces (like &lt;code&gt;Predicate&lt;/code&gt; here) and abstract classes. So the example can be further simplified:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def items = filter(source) { it.length()&amp;gt;3 } // &lt;b class=&quot;conum&quot;&gt;(1)&lt;/b&gt;
assert items == [&apos;foobar&apos;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;colist arabic&quot;&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;note that &lt;code&gt;as Predicate&lt;/code&gt; is not needed anymore!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can it be easier? Probably not, but maybe you noticed that this is close to what Java 8 will allow with lambdas:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;List&amp;lt;String&amp;gt; items = filter(source, String str -&amp;gt; str.length()&amp;gt;3)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you must be aware of some subtle differences with Java 8. One is that closures are &lt;strong&gt;not&lt;/strong&gt; lambdas but instances of the &lt;code&gt;Closure&lt;/code&gt; class (a subclass of &lt;code&gt;Closure&lt;/code&gt;, to be precise), while lambdas are converted at &lt;strong&gt;compile time&lt;/strong&gt; and can be directly implemented, for example, as methods (simple case) or anonymous inner classes. This difference implies that if you have:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def method(Closure c) { ... }
def method(SAMType arg) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then if you pass a closure as argument:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;method { ...do something... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;then the method which is chosen is the version which accepts a &lt;code&gt;Closure&lt;/code&gt;, not the version accepting a &lt;code&gt;SAMType&lt;/code&gt;. But since &lt;code&gt;Closure&lt;/code&gt; implements &lt;code&gt;Runnable&lt;/code&gt; and &lt;code&gt;Callable&lt;/code&gt;, the same is true for those two interfaces:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;def method(Runnable c) { ... }
def method(SAMType arg) { ... }
method { ...do something... } // will call method(Runnable)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that if you want to call the &lt;code&gt;SAMType&lt;/code&gt; version, you still have to use explicit coercion:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;method { ...do something... } as SAMType&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now that we exposed the basics of closure coercion, let&amp;#8217;s come to the topic that gave its name to this blog post: performance.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_performance_of_coercion_vs_closure&quot;&gt;Performance of coercion vs closure&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_gbench&quot;&gt;GBench&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We will discuss here the impact of using closure coercion and compare the cost of implicit/explicit closure coercion as compared with calling a method which directly accepts a closure. For that, let&amp;#8217;s start with the tool we&amp;#8217;re going to use: &lt;a href=&quot;https://code.google.com/p/gbench/&quot;&gt;GBench&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://code.google.com/p/gbench/&quot;&gt;GBench&lt;/a&gt; is a project I really like and that I use a lot. It&amp;#8217;s meant for micro-benchmarking. We know that micro-benchmarks are bad, but in some cases, they are useful. &lt;a href=&quot;https://code.google.com/p/gbench/&quot;&gt;GBench&lt;/a&gt; makes them a little better by providing a framework that does all the boring stuff that you have to do when micro-benchmarking:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;setting up timers&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;warm up&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;repeat the execution of the same code N times&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;generation of a report&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All this using a nice DSL. If you want to write benchmarks, time execution of some process in your Groovy program, make sure to use it, it&amp;#8217;s just the perfect tool.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_measurements&quot;&gt;Measurements&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now let&amp;#8217;s proceed with the measurements. We want to compute the cost of:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;directly accepting a closure as an argument&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;coercing the closure to a SAM type then calling&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For that, we&amp;#8217;re just defining a very simple SAM type and two helper methods:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;interface SAMType {
    void apply()
}

@groovy.transform.CompileStatic
void direct(Closure c) { c.call() }

@groovy.transform.CompileStatic
void coercion(SAMType s) { s.apply() }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The two methods that will be called are compiled statically so that we made direct method calls inside the method body. This allows us to measure precisely the cost of calling the method, rather than the cost of dynamic dispatch. The measurements are made using this code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;Closure cachedClosure = { &apos;do something&apos; }
SAMType cachedSAMType = { &apos;do something&apos; }

@Grab(group=&apos;org.gperfutils&apos;, module=&apos;gbench&apos;, version=&apos;0.4.2-groovy-2.1&apos;)
def r = benchmark {
      &apos;explicit coercion&apos; {
          coercion { &apos;do something&apos; } as SAMType
      }
      &apos;implicit coercion&apos; {
          coercion { &apos;do something&apos; }
      }
      &apos;direct closure&apos; {
          direct { &apos;do something&apos; }
      }
      &apos;cached SAM type&apos; {
          coercion cachedSAMType
      }
      &apos;cached closure&apos; {
          direct cachedClosure
      }
  }
  r.prettyPrint()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can see that we are testing 5 cases here:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;explicit coercion&lt;/code&gt; calls the method accepting a &lt;code&gt;SAMType&lt;/code&gt; with explicit coercion of a closure into a &lt;code&gt;SAMType&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;implicit coercion&lt;/code&gt; does the same, without &lt;code&gt;as SAMType&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;direct closure&lt;/code&gt; calls the method accepting a &lt;code&gt;Closure&lt;/code&gt;. This means that this version will &lt;strong&gt;not&lt;/strong&gt; involve any conversion.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cached SAM type&lt;/code&gt; calls the &lt;code&gt;SAMType&lt;/code&gt; version of the method with a coerced closure which is defined &lt;strong&gt;outside&lt;/strong&gt; of the scope of the benchmark method&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cached closure&lt;/code&gt; calls the &lt;code&gt;Closure&lt;/code&gt; version of the method with a closure which is defined &lt;strong&gt;outside&lt;/strong&gt; of the scope of the benchmark method&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last two versions are interesting because as I explained before, &lt;a href=&quot;https://code.google.com/p/gbench/&quot;&gt;GBench&lt;/a&gt; automatically repeats the execution of the code N times. This means that this code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;SAMType cachedSAMType = { &apos;do something&apos; }
// ...
&apos;cached SAM type&apos; {
    coercion cachedSAMType
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;is more or less equivalent to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;SAMType cachedSAMType = { &apos;do something&apos; }
// ...
10000.times {
    coercion cachedSAMType
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So here is the result of the execution of this benchmark:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Environment
===========
* Groovy: 2.2.0-rc-3
* JVM: Java HotSpot(TM) 64-Bit Server VM (23.5-b02, Oracle Corporation)
    * JRE: 1.7.0_09
    * Total Memory: 679.4375 MB
    * Maximum Memory: 1765.375 MB
* OS: Linux (3.8.0-22-generic, amd64)

Options
=======
* Warm Up: Auto (- 60 sec)
* CPU Time Measurement: On

                   user  system   cpu  real

explicit coercion  1258       0  1258  1259
implicit coercion  1102      12  1114  1115
direct closure      318       5   323   324
cached SAM type     263       0   263   265
cached closure      259       0   259   261&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What you can see from those results is that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;using implicit closure coercion is slightly faster than explicit closure coercion&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;having a method which accepts directly a closure can significantly improve performance (almost 4x faster dispatch!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;using a cached closure or a cached SAM type is fast in any case&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that using cached closures is not something that is specific to Groovy: it would be true for any Java code too, if you consider a coerced closure as an anonymous inner class. Each time the method is called, you create a &lt;strong&gt;new instance&lt;/strong&gt; of the closure (or, in Java, the anonymous inner class). So moving the definition of the closure (or anonymous inner class) outside the loop and you will reuse the &lt;strong&gt;same instance&lt;/strong&gt;, dramatically improving performance.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We must explain what performance we&amp;#8217;re talking about here: the closure does nothing special here, just returning a dummy string. So the cost of the treatment is almost null. What if the code actually does something? Would the differences be so important? To check that, we will modify the code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;interface SAMType {
    void apply()
}

@groovy.transform.CompileStatic
void coercion(SAMType s) { s.apply() }

@groovy.transform.CompileStatic
void direct(Closure c) { c.call() }

void doSomething() {
   Thread.sleep(100)
}

Closure cachedClosure = { doSomething() }
SAMType cachedSAMType = { doSomething() }

@Grab(group=&apos;org.gperfutils&apos;, module=&apos;gbench&apos;, version=&apos;0.4.2-groovy-2.1&apos;)
def r = benchmark {
      &apos;explicit coercion&apos; {
          coercion { doSomething() } as SAMType
      }
      &apos;implicit coercion&apos; {
          coercion { doSomething() }
      }
      &apos;direct closure&apos; {
          direct { doSomething() }
      }
      &apos;cached SAM type&apos; {
          coercion cachedSAMType
      }
      &apos;cached closure&apos; {
          direct cachedClosure
      }
  }
  r.prettyPrint()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this version, we simulate a long running process with &lt;code&gt;Thread.sleep(100)&lt;/code&gt;. The results are shown below:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;                     user  system     cpu       real

explicit coercion  248621       0  248621  100329258
implicit coercion  208407       0  208407  100273428
direct closure          0  166932  166932  100238245
cached SAM type         0  157406  157406  100232334
cached closure          0  160848  160848  100214197&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that it&amp;#8217;s better to look at the &lt;code&gt;real&lt;/code&gt; column here, since &lt;code&gt;Thread.sleep&lt;/code&gt; doesn&amp;#8217;t consume any CPU. What is interesting here is that now, there&amp;#8217;s almost no difference between each version. This is simply explained: the cost of the treatment exceeds the cost of instantiating a closure and coercing it.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So given those figures, what can we conclude? First of all, one of the interests of implicit closure coercion is that previously (before Groovy 2.2), if you wanted users to avoid explicit coercion, you had to write a method accepting a closure:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;// real method
void addListener(Listener listener) { ... }
// convenience method to avoid explicit coercion from user code
void addListener(Closure cl) { addListener(cl as Listener) }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem is that you double the number of methods here, so implicit closure coercion is a big bonus here. But our figures showed that calling a method accepting a closure is much faster, so you have a dilemn here: should you keep the closure version or not? The second benchmark gives a first answer: you shouldn&amp;#8217;t remove the &lt;code&gt;Closure&lt;/code&gt; version only if you know that the treatment in the closure is &lt;strong&gt;very&lt;/strong&gt; fast. As soon as business code in the closure is a bit complex, it&amp;#8217;s not worth it and you can remove the &lt;code&gt;Closure&lt;/code&gt; version. This means that in the vast majority of cases, you can remove it without problem.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In fact, there&amp;#8217;s one more case where you&amp;#8217;d want to keep the &lt;code&gt;Closure&lt;/code&gt; version: if you manipulate the closure before calling it, like changing the delegate:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code data-lang=&quot;groovy&quot;&gt;void doSomething(SAMType arg) { ... }
void doSomething(Closure cl) {
   def clone = cl.rehydrate(delegate,this,this)
   doSomething(clone as SAMType)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hope things are clearer for you now!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>A new home!</title>
      <link>https://melix.github.io/blog//2013/11/21/a_new_home.html</link>
      <pubDate>Thu, 21 Nov 2013 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2013/11/21/a_new_home.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Goodbye JRoller, welcome GitHub! Eventually, I migrated my blog to &lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub pages&lt;/a&gt;. It is a now a statically generated website.
What is interesting here is how I migrated contents from my &lt;a href=&quot;https://jroller.com/melix&quot;&gt;old blog&lt;/a&gt;. I used a &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt; script which
downloaded the old pages, converted them into &lt;a href=&quot;https://asciidoctor.org&quot;&gt;Asciidoctor&lt;/a&gt; format so that they can be statically processed by &lt;a href=&quot;https://jbake.org&quot;&gt;JBake&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Should you need something similar, I pushed this little toy here: &lt;a href=&quot;https://github.com/melix/jroller-export&quot; class=&quot;bare&quot;&gt;https://github.com/melix/jroller-export&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now the export is quite raw, there are probably minor rendering issues to fix, or broken links, and I still have to integrate:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;twitter/google+ share buttons&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;comments&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But this is another story!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, this blog is also published on GitHub and all posts are published under &lt;a href=&quot;https://creativecommons.org/licenses/by-nc-sa/2.0/en/&quot;&gt;Creative Commons by-nb-sa&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>deck2pdf: Exporting HTML5 slide decks to PDF</title>
      <link>https://melix.github.io/blog//2013/07/30/deck2pdf_exporting_html5_slide_decks.html</link>
      <pubDate>Tue, 30 Jul 2013 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2013/07/30/deck2pdf_exporting_html5_slide_decks.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_exporting_your_awesome_html5_presentation_to_pdf&quot;&gt;Exporting your awesome HTML5 presentation to PDF&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For some time now, I’ve started using &lt;a href=&quot;https://imakewebthings.com/deck.js/&quot;&gt;deck.js&lt;/a&gt; to write my talks. One of the reasons I do this is that it saves me &lt;strong&gt;lots&lt;/strong&gt; of time when I have to copy and paste code, because I can rely on javascript code highlighting libraries to do the job. I can focus on contents instead of rendering. If I had a better knowledge of CSS, too, I could certainly write impressive presentations (but unfortunately, no, I’m not good at CSS).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem with HTML5 slideshows is that you are often asked to upload your slides as PDF. For example, &lt;a href=&quot;https://speakerdeck.com/&quot;&gt;SpeakerDeck&lt;/a&gt;, &lt;a href=&quot;https://www.slideshare.net/&quot;&gt;SlideShare&lt;/a&gt; or &lt;a href=&quot;https://www.parleys.com/&quot;&gt;Parleys&lt;/a&gt; all require you to upload slides as PDF. None of them supports HTML5 (which is understandable because there are many frameworks available). While I did find some libraries that did the job (often in Perl or Ruby), I never managed to find one that actually worked properly.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_deck2pdf&quot;&gt;Deck2pdf&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s where it all started. I knew that JavaFX2 provided a WebView, which allowed rendering HTML pages with WebKit. What if I could use it to render my slide deck and export it to PDF? &lt;a href=&quot;https://github.com/melix/deck2pdf&quot;&gt;deck2pdf was born!&lt;/a&gt;. I started with something that was able to export my &lt;a href=&quot;https://imakewebthings.com/deck.js/&quot;&gt;deck.js&lt;/a&gt; presentations, but I figured out very quickly that it could support other HTML5 presentation libraries quite easily. As of today, &lt;a href=&quot;https://github.com/melix/deck2pdf&quot;&gt;deck2pdf&lt;/a&gt; supports:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://imakewebthings.com/deck.js/&quot;&gt;deck.js&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://lab.hakim.se/reveal-js&quot;&gt;reveal.js&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://bartaz.github.io/impress.js&quot;&gt;impress.js&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and &lt;a href=&quot;https://github.com/paulrouget/dzslides&quot;&gt;DZSlides&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But more importantly, if your favorite HTML5 slideware is not supported, adding custom profiles is supported and fairly easy! Adding support for another library is as simple as adding a descriptor file with the javascript commands inside. For example, here’s how the &lt;a href=&quot;https://imakewebthings.com/deck.js/&quot;&gt;deck.js&lt;/a&gt; profile is written:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;totalSlides=$.deck(&apos;getSlides&apos;).length
nextSlide=$.deck(&apos;next&apos;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s all! Support for more complex interactions is also provided using Groovy profiles, like for example in &lt;a href=&quot;https://bartaz.github.io/impress.js&quot;&gt;impress.js&lt;/a&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;setup = {
    js &apos;var api = impress();&apos;
    js &apos;&apos;&apos;var $$ = function ( selector, context ) {
        context = context || document;
        return context.querySelectorAll(selector);
    };&apos;&apos;&apos;
    js &apos;&apos;&apos;var byId = function ( id ) {
        return document.getElementById(id);
    };&apos;&apos;&apos;
}

nextSlide = {
    js(&apos;api.next()&apos;)
}

totalSlides = {
    js (/$$(&quot;.step&quot;, byId(&apos;impress&apos;)).length/)
}

// longer pause because of transitions
pause = 2000&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, &lt;a href=&quot;https://github.com/melix/deck2pdf&quot;&gt;deck2pdf&lt;/a&gt; is open source and licensed under &lt;a href=&quot;https://www.apache.org/licenses/LICENSE-2.0.html&quot;&gt;APL2&lt;/a&gt;. Feel free to fork it and contribute new profiles! The home page of the project has documentation explaining how you can create your own. I’m waiting for your pull requests!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>GR8Conf Europe 2013 is over</title>
      <link>https://melix.github.io/blog//2013/05/27/gr8conf_europe_2013_is_over.html</link>
      <pubDate>Mon, 27 May 2013 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2013/05/27/gr8conf_europe_2013_is_over.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gr8conf_europe_2013&quot;&gt;GR8Conf Europe 2013&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last week I spoke at &lt;a href=&quot;https://gr8conf.eu/index&quot;&gt;GR8Conf Europe&lt;/a&gt; for the second time. As last year, the content of the conference was really amazing and highly technical. While the conference started with a University day on May, 22, we took advantage of the conference to organize a Groovy DevCon the day before. A Groovy DevCon is basically a physical meeting for the Groovy Core developers, where we share ideas and eventually make decisions with regards to the future of Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This year, several well-known Groovy gurus participated in the meeting:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/glaforge&quot;&gt;Guillaume Laforge&lt;/a&gt;, the Groovy project lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;https://[Jochen ``Blackdrag&apos;&apos; Theodorou], the Groovy technical lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/mittie&quot;&gt;Dierk Koenig&lt;/a&gt;, Groovy committer and main author of the famous Groovy in action book&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/aalmiray&quot;&gt;Andrés Almiray&lt;/a&gt;, the Griffon lead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/CedricChampeau&quot;&gt;myself&lt;/a&gt;, Groovy Core committer&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But we had a special guest, &lt;a href=&quot;https://gr8conf.eu/Speakers/Juergen-Hoeller&quot;&gt;M. Juergen Hoeller of Spring fame&lt;/a&gt; himself!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The meeting was really useful. On my side, I was particularily happy with the discussions regarding Groovy and Java 8, where we eventually took the (long awaited for me) decision to provide some automatic coercion of closures to interfaces. Basically, this means that you would no longer have to write:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    interface Callback {
        void execute()
    }
    void onEvent(Callback c) { c.execute() }

    onEvent({println &apos;hello&apos;} as Callback)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But instead, you will be able to write directly:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    interface Callback {
        void execute()
    }
    void onEvent(Callback c) { c.execute() }

    onEvent {println &apos;hello&apos;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This will lead to easier to read and maintain code. We discussed some limitations for the feature, but for a large number of cases, this would work directly. You can expect this feature to appear in Groovy 2.2.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_ast_transformations_unleashed&quot;&gt;AST transformations unleashed&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The University day was the occasion for me to give a workshop about AST transformations. For GR8Conf Europe, I had the chance to do it with &lt;a href=&quot;https://twitter.com/aalmiray&quot;&gt;Andrés Almiray&lt;/a&gt;, the Griffon lead, but also one of the most talented programmer of the Java community. Andrés started with a small introduction about AST transformations, then I continued the workshop with &lt;a href=&quot;https://github.com/melix/ast-workshop&quot;&gt;a series of exercises&lt;/a&gt; (that you can take for yourself). Unfortunately, two hours and a half didn’t give us enough time to complete all exercises but I was quite happy with the session. I really hope this gave ideas to some people in the room, and that it provided the necessary bits to get started. Note that if you missed it, I will give the same workshop at &lt;a href=&quot;https://gr8conf.us/index&quot;&gt;GR8Conf US in Minneapolis&lt;/a&gt;, so register now!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_type_checking_your_dsls&quot;&gt;Type checking your DSLs&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I gave my second talk on Friday, last day of the conference. It was named &lt;a href=&quot;https://gr8conf.us/Presentations/Type-checking-your-DSLs&quot;&gt;Type checking your DSLs&lt;/a&gt;. While I already gave this talk 3 times before (G&amp;amp;G exchange, Greach and Devoxx France), I always like to change some contents to adapt to the audience and have some novelties inside. Unfortunately, for technical reasons, this talk went really bad for me. I assume people felt it, but I was quite disconcerted. The reason is that most of my talk relies on commenting code, but that I wasn’t able to show it properly! Even if the projectors were supposed to support full-HD through HDMI, for some obscure reason, my laptop wasn’t able to ``discover&apos;&apos; the HDMI output, and I was stuck to a 1024x768 VGA output. Worse than that, on screen, the borders were cut. This was the first time this ever happened to me, and to be honest, it completely troubled me. I wasn’t able to show code properly, so I wasn’t able to keep track of what I wanted to say. This was a horrible experience, but I hope people get the idea, as I only managed to give a rough idea of what I wanted to say :-( You know, that feeling when you try to explain something, and that people look at you as if you were an extraterrestrial…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I will give the same talk at Minneapolis later this year, so I sincerely hope things will go better, especially because I really like this talk, which gives a lot of hints on the power of the language, combining several features available in Groovy 2.1. All the (uncut) slides are available &lt;a href=&quot;https://github.com/melix/gr8confeu2013&quot;&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Going to GR8Conf for the second time was like last year an incredible experience. I had the chance to talk to lots of talented and famous developers of the Groovy community, as well as sharing with users, which is worth the trip. This gave me for example the occasion to talk to two GPars brains for the first time (Dierk Koenig and Vaclav Pech). I’d really like to thank Soren for organizing this, as well as the crew for all the goodness that we can see here. I’m really looking forward to go to the next edition!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Null-safe invocation and primitive types</title>
      <link>https://melix.github.io/blog//2013/04/17/null_safe_invocation_and_primitive.html</link>
      <pubDate>Wed, 17 Apr 2013 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2013/04/17/null_safe_invocation_and_primitive.html</guid>
      	<description>
	&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_null_safe_method_invocation&quot;&gt;Null-safe method invocation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yesterday, I worked on &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY-6101&quot;&gt;a bug&lt;/a&gt; reported on the static compiler of Groovy. It appeared that the underlying problem was related to how null-safe invocations are handled when the expected return type is a primitive. Let’s take an example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class Person {
   String name
   int age
}

Person getPerson() { null }

Person p = getPerson()

def result = p?.age&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now the question is, what is the value of &lt;em&gt;result&lt;/em&gt;? If you run this in the Groovy console, the result would be &lt;em&gt;null&lt;/em&gt;. This is compatible with the assumption that the null-safe invocation operator (?.) always return null if the receiver of the message is null (here, &lt;em&gt;p&lt;/em&gt; is null, so result is null). The definition is pretty easy, but it gets more complicated if you slightly modify the code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;int result = p?.age&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;By explicitely setting the type to &lt;em&gt;int&lt;/em&gt;, executing this would throw an error, stating that you cannot convert &lt;em&gt;null&lt;/em&gt; to &lt;em&gt;int&lt;/em&gt;. It makes sense knowing that the null-safe invoker is supposed to return null if the receiver is null, but it starts getting strange as if &lt;em&gt;p&lt;/em&gt; is not null, the assignment is perfectly valid since &lt;em&gt;getAge()&lt;/em&gt; is expected to return a primitive type… This means that unlike the ``normal&apos;&apos; invoker which is guaranteed to keep the method return type untouched, the null-safe invoker does not honor the method signature.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_dynamic_world&quot;&gt;The dynamic world&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What if the null-safe invoker was aware of the return type? In &lt;code&gt;null-safe&apos;&apos;, you must think about what the &lt;/code&gt;safe&apos;&apos; part stands for. It’s definitely the receiver, because you want the invocation to be safe (not failing) if the receiver is null. If the &lt;strong&gt;receiver&lt;/strong&gt; is null, then return null. This means that because &lt;em&gt;p&lt;/em&gt; is null, it chooses to return null, independently of the method that was supposed to be called. Here, the method was &lt;em&gt;getAge()&lt;/em&gt;, which is supposed to return a primitive type. As null is not a primitive, I would expect the null-safe invoker to return a &lt;em&gt;default value&lt;/em&gt; compatible with the primitive type. This means that here, I would expect the null-safe invoker to return &lt;em&gt;0&lt;/em&gt;. Now, what is the problem with returning a default value? First of all, we’re in a dynamic world. This means that when &lt;em&gt;p?.age&lt;/em&gt; is executed, the target method hasn’t been chosen, because you need to know the runtime type of &lt;em&gt;p&lt;/em&gt; to determine what method will eventually be called. As &lt;em&gt;p&lt;/em&gt; is null, the dynamic runtime doesn’t know the type of &lt;em&gt;p&lt;/em&gt;, so has no idea that calling &lt;em&gt;age&lt;/em&gt; would return a primitive type. Conclusion, in a dynamic world, the null-safe invoker must always return null, even if the expected method would return a primitive…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_static_world&quot;&gt;The static world&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now what if we’re in a pure static world? In that case, the method to be called is chosen at compile time, given the inferred type of &lt;em&gt;p&lt;/em&gt;. It means that unlike the dynamic runtime, the static compiler, at this point, knows that &lt;em&gt;p.age&lt;/em&gt; is &lt;em&gt;p.getAge()&lt;/em&gt; which returns a primitive type. So it is capable of handling the null-safe invocation with what I think is better, semantically speaking: &lt;em&gt;null-safe&lt;/em&gt; invocation only checks the receiver, and returns a value which depends on the return type of the method being invoked. So a static compiler is able to return &lt;em&gt;0&lt;/em&gt; instead of the non-pritive &lt;em&gt;null&lt;/em&gt;. What is funny is that I asked, on Twitter, what people expected from the result of &lt;em&gt;p?.getAge()&lt;/em&gt; if &lt;em&gt;p&lt;/em&gt; is null. Everybody answered &lt;em&gt;null&lt;/em&gt;. So it’s clear that my way of thinking is not mainstream, but I’m ok with that. I just find it awkward that an operator which is supposed to act on invocation is also capable of altering the return type…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Anyway, even if it’s possible for the static compiler to return a default value, the fix I pushed doesn’t do that. It will always return null. The main reason for doing that is not that it was easier to fix (it’s quite the opposite), but that it keeps the semantics of statically compiled Groovy equal to those of dynamic Groovy. As it’s not possible for the runtime to know what the method would return, always returning null is fine, even if some situations (static compilation), you know a bit more what would happen :)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Les écoles sont-elles le problème ?</title>
      <link>https://melix.github.io/blog//2013/03/26/les_%C3%A9coles_sont_elles_le.html</link>
      <pubDate>Tue, 26 Mar 2013 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2013/03/26/les_%C3%A9coles_sont_elles_le.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comme beaucoup, j’ai appris aujourd’hui la création d’une école de développement lancée par Xavier Niel. Mais dans cette annonce, j’ai été choqué par plusieurs choses, à commencer par cette citation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Aujourd’hui, le système français ne marche pas. Il est coincé entre d’une part l’université, qui propose une formation pas toujours adaptée aux besoins des entreprises mais qui est gratuite et accessible au plus grand nombre, et d’autre part les écoles privées, chères, dont la formation est assez qualitative mais laisse sur le côté de la route le plus grand nombre de talents, voire de génies, que nous pourrions trouver en France.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Qu’est-ce qu’essaie de dire Xavier Niel ici ? Que seule les écoles privées sont capables de fournir une formation de qualité ? Que parce que l’Université est ouverte au plus grand nombre, la qualité n’est pas au rendez-vous ? Mais quid des IUT, quid des écoles d’ingénieur publiques (INSA, réseau Polytech’ dont je suis issu, …) ? Je ne doute pas que la citation ci-dessus ait volontairement omis ces organismes &lt;strong&gt;publics&lt;/strong&gt;, qui sont j’ose le croire capables de formations modernes, techniques et dont les professeurs sont au moins aussi dévoués que ceux du privé !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il ne s’agit pas non plus d’un problème de sélection de talents à l’entrée, car ici, contrairement à la Faculté qui se doit d’accueillir quiconque s’inscrit, les IUT et autres écoles d’ingénieur publics ont un processus de sélection à l’entrée. Et sur ce point, j’ai une petite anecdote à vous raconter. Il y a deux ans, lorsque j’ai changé d’entreprise, j’ai eu besoin de récupérer mon diplôme d’ingénieur (oui, parce qu’on me demandait de prouver que j’étais ingénieur) et je suis donc retourné à mon ancienne école, Polytech’Nantes, où j’ai croisé un ancien professeur. Au détour de la conversation, j’ai appris qu’il y avait &lt;strong&gt;moins&lt;/strong&gt; de candidats à l’entrée de l’école qu’il y a 10 ans. Visiblement, les &lt;code&gt;nouvelles technologies&apos;&apos; n’attirent plus autant qu’avant. Ils avaient donc, à l’époque, un problème de sélection à l’entrée pour trouver des étudiants, tout simplement, sans parler de trouver des talents. A ce propos, je rejoins quand même Xavier Niel sur un point (du moins, si je lis entre les lignes). Les écoles d’ingénieur privées en France, on les choisit surtout parce que c’est marketing, ça fait bien sur un CV de sortir d’Epitech. Au passage, si tu es étudiant et que tu lis ces lignes, méfie toi des écoles qui ne donnent pas droit à un diplôme d’Etat en sortie, car comme tu l’as constaté, c’est utile… Ces écoles, on y entre souvent parce qu’on a les moyens de payer. Bref, c’est plus un investissement qu’un problème de qualité de formation… En pratique, il reste à démontrer qu’un ingénieur sorti d’une école privée est &lt;/code&gt;meilleur&apos;&apos; qu’un autre…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors pour rire un peu, lisons &lt;a href=&quot;https://www.42.fr/wp-content/uploads/2013/03/programme-42.pdf&quot;&gt;le programme de l’école 42&lt;/a&gt;: Merise, XWindow, Corba, J2ME, que des technologies toutes neuves et incroyablement répandues dans l’industrie… j’avais les mêmes cours lorsque je suis rentré à l’IRESTE en 1999 ! Alors, certes, il y a du HTML5 au programme, de l’iOS et Android. En revanche, je cherche encore Spring, le framework alternatif à JEE le plus répandu dans l’industrie, Scala (ou encore Groovy, rêvons un peu). En clair, ce programme existe aussi dans n’importe quelle autre formation, y compris dans le public. Je vous conseille d’ailleurs, au sujet d’iOS, cet &lt;a href=&quot;https://plus.google.com/106143787836384076615/posts/Sb1yDrKsYcP&quot;&gt;&quot;&amp;gt;excellent post de Julien Ponge&lt;/a&gt; sur l’abandon de l’enseignement d’iOS à l’INSA Lyon (Ecole d’ingénieur publique, faut-il le rappeler). En clair, ce programme, si intéressant soit-il, n’a rien de révolutionnaire. C’est un classique qu’on trouve dans n’importe quelle école. Ce à quoi on pourrait me dire que ça n’est pas dans le programme mais dans la façon de l’enseigner que se trouve la clé, mais là, je demande à voir. Il y a des cours, il faut bien les suivre. Si c’est faire des projets annexes pour bidouiller, etc, c’est sympa, mais ça, on le fait depuis longtemps ailleurs aussi. Non, je ne vois pas trop…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le problème n’est donc certainement pas dans les programmes, ni dans la sélection. Ce qui m’amène à parler des raisons pour lesquelles les gens comme moi en viennent à choisir l’informatique. Je les divise en deux catégories:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ceux qui sont passionnés, tombés dedans quand ils étaient petits: j’en fais partie. J’ai commencé à coder à 8 ans, je n’ai jamais arrêté depuis. C’est une passion autant qu’un boulot et rares sont ceux qui comme moi parviennent à combiner les deux.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ceux qui y vont parce qu’il y a du travail : on ne cesse de le répéter, on manque de main d’oeuvre dans l’informatique. Ca n’est (pour l’instant) pas trop mal payé, et donc on y va parce qu’on peut bien manger. J’en ai croisé beaucoup et j’en croise encore.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans la première catégorie, je classe les professeurs. S’il existe un vrai problème, ça n’est certainement pas l’enseigement, ni les programmes. Non, l’informatique souffre d’un problème de reconnaissance, et il existe à de multiples niveaux. Le premier, c’est celui de l’enseignement. Lorsque j’étais étudiant, j’ai commencé par faire un DEUG, puis j’ai choisi de ne pas suivre la voie de la recherche (doctorat) et de poursuivre en école d’ingénieur. Etait-ce le programme qui était en cause ? Non, certainement pas. Etait-ce le problème des classes surchargées et du fait de ne pas être choyé ? Non plus: j’étais extrêmement heureux de l’autonomie qu’ont les étudiants de Fac, tout comme j’étais totalement dans l’esprit de devoir travailler fortement à la maison pour compenser le manque de travaux &lt;code&gt;individualisés&apos;&apos;. Non, le vrai problème, c’est le salaire. Le calcul était simple: en sortie d’école, je toucherai autant, voire plus, avec un diplôme d’ingénieur que mon prof à l’Université. Et lui était incontestablement plus compétent que moi. Alors, être professeur en France, aujourd’hui, c’est de la dévotion pure et simple. Je l’ai déjà dis en privé à certains, je le confirme : je vous admire les gars. Alors j’ai choisi l’école d’ingénieur (publique, pas question d’aller dans le privé). Là encore, je caricature un peu, l’idée de l’école était aussi qu’elle était plus proche du monde de l’entreprise et que la voie &lt;/code&gt;universitaire&apos;&apos; avec carrière définie à l’avance, les mutations et autres ne m’enchantait guère, mais ça c’est un autre débat…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Bref, pour entrer, sélection à l’entrée. Il fallait montrer patte blanche, passer un entretien avec un professeur et un chef d’entreprise, avoir de bons résultats et faire partie des heureux élus (la sélection comptait 1/3 de l’université, 1/3 de l’IUT, 1/3 de prépas). Une fois entré, le plus dur est fait. On passe 3 ans à suivre ses cours, à s’améliorer, mais je regretterai toujours l’ambiance de la fac, les révisions autour d’un café, les impressions de polys, … Il est clair que les moyens de l’école étaient plus élevés, par rapport à la fac, et qu’on est entre de bonnes mains. A moins de faire l’idiot, difficile de ne pas en sortir avec un diplôme. Mon attachement à la fac et au monde de la recherche ne s’est pas arrêté à l’entrée à la fac, non, puisque j’ai décidé de faire en parallèle un DEA en informatique, possibilité qui était offerte par l’école à l’époque. On devait alors suivre des cours supplémentaires à la Fac. J’y ai appris beaucoup, de personnes brillantes. Alors, à l’école, j’ai aussi eu des professeurs moins ``bons&apos;&apos; que d’autres, mais franchement, même en entreprise, on trouve de sacrés boulets, ça n’a rien à voir avec le fait qu’on soit dans une école publique.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans le cadre de mon double diplôme ingénieur/DEA, j’ai eu la chance de participer à la création d’une entreprise issue d’un projet de recherche, qui m’a embauchée à ma sortie d’école… Je n’aurais pas choisi un autre type d’entreprise. En particulier, je fuis les SSII et je cherche plutôt des éditeurs de logiciels.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pourquoi ce choix ? Parce que je pense que les SSII font partie du problème en France. La formation technique à l’école n’était pas un problème mais il est clair qu’on nous met dans un état d’esprit plus que douteux allant directement dans le sens des SSII. Des cours de management, c’est intéressant, mais pourquoi s’enfoncer dans ce modèle détestable qui consiste à croire qu’au bout de 2 ans, on n’est plus capable de développer et qu’il faut passer chef de projet ? Alors certes, la catégorie 2 des personnes dont j’ai parlé plus haut s’en accomodent très bien, mais il est stupide de croire qu’un bon ingénieur ferait un bon chef de projet, tout comme il est stupide de ne proposer des augmentations de salaires qu’en changeant de poste et en passant à un poste de management. Si les entreprises, SSII en tête, prenaient moins les ingénieurs pour de la chair à commercial, on s’en sortirait déjà beaucoup mieux (nous les ingénieurs, l’entreprise, elle, c’est moins sûr). Même après 2 ans d’expérience, on est très loin d’avoir un niveau de compétence suffisant pour égaler la productivité d’un senior. Les experts, ça existe, et il faut les respecter. Le vrai problème est là: le respect du développeur. Le choix de devenir développeur senior est très difficile en France, de part cet aspect social assez négatif (non mais allô quoi ? T’as 30 ans et t’es développeur ? Non mais allô !) et le fait qu’avec l’âge, on aimerait bien s’offrir une maison quand même…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au sujet des SSII, j’ai une petite anecdote. Il y a quelques années, l’entreprise pour laquelle je travaillais se portait assez mal, et donc par précaution j’ai commencé à passer des entretiens d’embauche. J’ai mis mon CV sur &lt;code&gt;Les Jeudis&apos;&apos; et à peine quelques heures plus tard, j’avais déjà décroché un entretien… dans une SSII. Comme il faut bien manger et que les offres des éditeurs ne courent pas les rues (à mon grand désespoir), je suis allé à cet entretien en le prenant comme un entraînement. Et heureusement. Pour l’entretien, j’ai été confronté à un potentiel futur &lt;/code&gt;supérieur&apos;&apos;, un commercial en fait qui m’a présenté cette &lt;code&gt;grande SSII leader en France, n’embauchant que des dieux&apos;&apos; (je caricature à peine). D’une part, se dire qu’un ingénieur se trouve hiérarchiquement lié à un commercial me pose un sérieux problème. C’est qu’on vend un profil avant de vendre mes compétences. Il n’y avait aucun travail à me proposer. On m’a convonqué pour avoir un CV dans une base et le vendre à des clients. Ca n’est donc pas parce qu’il y avait un projet qu’on m’a convoqué, mais parce que potentiellement, je suis vendable. Alors, comme j’ai la chance d’être dans un domaine où il y a encore (un peu) de choix dans les offres d’emploi, non merci. Mais le plus choquant dans cet entretien, pour moi, ce fut la question finale, faite par ce commercial: &lt;/code&gt;pourriez-vous me résumer ce qu’on a dit dans cet entretien&apos;&apos;. J’ai trouvé cette question humiliante. Déjà, j’étais venu en me disant qu’on avait un projet à me proposer, mais non, je commercial ne savait même pas que je n’avais pas postulé, mais qu’on m’avait cordialement invité à passer un entretien. Ensuite, mon égo en a pris un coup par cette question, qui sous-entend que je ne suis pas assez professionnel pour avoir compris le discours élitiste et commercial que l’on m’avait longuement rabaché dans cet entretien. Le lissage et la lobotomisation avait déjà commencé. Evidemment, on ne m’a pas rappelé et je ne m’en porte pas plus mal.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ne soyons pas caricatural non plus, je suis certain d’être ``mal tombé&apos;&apos;, mais au final, j’avais mon opinion sur les SSII et cet entretien n’a fait que la conforter. Il existe sûrement des sociétés plus petites où on n’est pas uniquement un CV dans une base…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ce qui m’amène à un dernier point. Je suis un amoureux de l’esprit open source. Aujourd’hui, j’ai la chance d’en vivre et j’aimerais que beaucoup plus de développeurs puissent le faire. Ne serait-ce que pour redécouvrir leur métier. J’ai toujours rêvé de travailler dans une entreprise faisant de l’open-source, et quand je dis faisant de l’open-source, je ne veux pas dire utilisant des projets open source, non, je veux dire qui contribue directement à des projets OSS. Cet esprit me vient probablement de tout petit, lorsqu’à 10 ans, j’achetais ces revues dont j’ai oublié le nom, où je pouvais recopier le code source d’un jeu sur mon CPC, et après de longues heures de recopie, être émerveillé par ce que je venais d’accomplir.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors, oui, à l’époque, je n’inventais pas grand chose, mais je voulais et je pouvais bidouiller. Et je pense qu’il n’y a rien de plus instructif, en informatique, que la bidouille. Triturer du code, recopier, modifier, lorsqu’on est enfant, il n’y a rien de plus simple et on apprend énormément (aaaahhh, et donc là, je peux faire de l’overscan !). Il n’empêche qu’à une époque, j’ai eu besoin de structurer tout celà et que c’est à l’Université que ça s’est fait (comprendre les concepts qu’on manipule).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Au quotidien, l’open source tel que je le pratique à de nombreux avantages. D’abord, je suis consommateur. Je ne comprends pas ce que fait une fonction, j’ouvre le code, je le lis. Je peux aussi profiter du code et de l’expérience des autres (si tant est que la licence le permette). D’un autre côté, je contribue. Et en tant que développeur, je trouve que c’est extrêmement formateur. Lorsque j’ai commencé à développé sur Groovy, je pensais ne pas être mauvais (comme 90% des développeurs, je pense être meilleur que ma moyenne ;-)), pour autant, lorsque je lisais le code de nombreux projets open source, je me trouvais petit. Et encore aujourd’hui, je le suis, mais j’apprend. Faire de l’open-source, c’est par définition montrer son code à tout le monde, et en pratique, on n’aime pas spécialement montrer une mauvaise image de soi. Etre scruté par des milliers, voire millions d’yeux, c’est très formateur et ça pousse à s’améliorer. Ca ne veut pas dire qu’on ne fait pas de la m…, mais en tout cas, on la limite et si on en produit, on est vite rappelé à l’ordre… J’aime ce métier parce que je vois directement les résultats de ce que je produis : des utilisateurs contents (ou pas) et je n’ai rien à leur cacher. Bref, les qualités intrinsèques de mon ``produit&apos;&apos; passent avant toute chose. L’un des bons côtés de mon métier, c’est se balader dans une conférence et croiser quelqu’un qui vous dit que ce que vous avez fait lui a sauvé sa journée. C’est peut de chose, mais ça montre que le dev open source est avant tout tourné vers l’autre. Si je ne pouvais lire le code des autres, je ne mesurerais pas la marge de progression que j’ai et j’apprendrais beaucoup moins, ce qui signifie, au bout du compte, une qualité moindre et une dévalorisation générale du métier…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alors non, clairement, je ne pense pas que le problème, en France, ce soit les écoles. Je ne crois pas non plus que le problème soit les enseignants, ou le public vs le privé. Et je ne crois pas qu’on perde des talents à cause d’un problème de sélection. Non, le problème, c’est la reconnaissance du métier. Faire que les gens soient fiers de leur travail et puissent en vivre dignement. En particulier, le problème du salaire des profs est à mon humble avis critique et explique que la France laisse disparaître des talents dans les méandres des inter-contrats. Non, commençons par définir des projets, faciliter l’innovation, arrêter de penser franco-français (le financement public du ``Cloud Français&apos;&apos; est un pur gaspillage, à mon humble avis) et défendons au contraire ce qui permet de faire émerger les talents: ouverture, neutralité du net, reconnaissance du travail. Arrêtez de demander des stagiaires avec 5 ans d’expérience. Bref, faites nous rêver !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Nous faire rêver, effectivement, Xavier Niel sait le faire, on peut lui reconnaître ça. En pratique, je ne suis pas convaincu de la solution, parce que je ne suis pas convaincu que le problème soit là. A moins que de cette école n’émerge une technique nous permettant de lire des vidéos YouTube sans saccade :-)&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Static builders inception</title>
      <link>https://melix.github.io/blog//2013/02/13/static_builders_inception.html</link>
      <pubDate>Wed, 13 Feb 2013 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2013/02/13/static_builders_inception.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_documentation_is_good_for_everybody&quot;&gt;Documentation is good for everybody&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As part of the &lt;a href=&quot;https://groovy.329449.n5.nabble.com/ANN-Documentation-effort-and-site-redesign-tp5712875.html&quot;&gt;Groovy documentation effort&lt;/a&gt;, I started writing documentation for several features of Groovy, including &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Advanced+compiler+configuration&quot;&gt;compiler configuration&lt;/a&gt;, &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Type+checking+extensions&quot;&gt;type checking extensions&lt;/a&gt;, and yesterday the &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/The+@DelegatesTo+annotation&quot;&gt;@DelegatesTo annotation&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is interesting when you do so, apart from the fact that this should have been done much sooner, is that it is interesting for our users, of course, but also for us. In particular, when I wrote the statically compiled builder example in the &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/The+@DelegatesTo+annotation&quot;&gt;@DelegatesTo documentation&lt;/a&gt;, I found myself thinking there was a lot of repetitive code in there… And that gave me a new idea…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the following post, I will show you how I combined several features of Groovy 2.1 to provide an implementation of a statically compiled HTML builder: static compilation, @DelegatesTo, meta-annotations, custom type checking extensions and of course AST transformations, without having to write all the boilerplate necessary to make it type safe! Nothing less…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_statically_compiled_markup_builder&quot;&gt;Statically compiled markup builder&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What if we could annotate a class as a markup builder, describe its schema, then, if a user wants to statically compile the builder usage, have a type-safe, statically compiled builder? That means, if you write this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@groovy.transform.CompileStatic
String build() {
    def builder = new HTMLBuilder()
    builder.html {
        body {
            p {
                out &amp;lt;&amp;lt; &quot;Hello, this is &quot;
                a(href:&apos;https://groovy.codehaus.org&apos;) { out &amp;lt;&amp;lt; &apos;Groovy&apos; }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then you want &lt;strong&gt;compile-time errors&lt;/strong&gt; if any of the tags used in the builder is not recognized or at the wrong place. As you know, builders are normally dynamic in Groovy, but the documentation for &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/The+@DelegatesTo+annotation&quot;&gt;@DelegatesTo documentation&lt;/a&gt; showed that it was possible to create a statically checked (and statically compiled) builder.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There were two problems in the approach from the documentation:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;unnecessary repetitive/verbose code (inner classes)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;no ability to perform checks on the allowed attributes of a tag at &lt;strong&gt;compile-time&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_here_comes_the_statically_compiled_markup_builder_experiment&quot;&gt;Here comes the statically compiled markup builder experiment!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_night_hacker&quot;&gt;The night hacker&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So last night, I started an experiment to see if I could make things easier and after two hours of coding, I had indeed a first working implementation, which allowed me to define a schema for my builder, but didn’t check attributes yet.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today, I spent several hours fixing bugs for Groovy 2.1.1, including some that prevented me from going further (including one with nasty classloading issues that prevented Gradle from loading some classes from my AST transformation…). After that, I could eventually fix my prototype and I now have a fully working implementation…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_checking_out_the_sources&quot;&gt;Checking out the sources&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, all the code is available on &lt;a href=&quot;https://github.com/melix/staticbuilder&quot;&gt;GitHub&lt;/a&gt;. It makes uses of the gradle wrapper, so all you need is to run:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    $ ./gradlew test&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_builder&quot;&gt;The builder&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Creating a statically checked builder is easy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    import groovyx.transform.StaticMarkupBuilder

    @StaticMarkupBuilder
    class HTMLBuilder {
        static schema = {
            html {
                head { title() }
                body {
                   p()
                   a(attributes:[&apos;href&apos;, &apos;target&apos;])
                }
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For examples of several builders, you can take a look at the &lt;a href=&quot;https://bit.ly/XAOvhJ&quot;&gt;unit test&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is important here is that using the &lt;strong&gt;@StaticMarkupBuilder&lt;/strong&gt;, we are not using a builder, we are defining one:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a statically compiled builder&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;which accepts a predefined schema&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, the schema is very simple. It says that at the top level, we can find the &lt;em&gt;html&lt;/em&gt; tag. This tag can include either a &lt;em&gt;head&lt;/em&gt; or a &lt;em&gt;body&lt;/em&gt; tag. Below body, you can find either &lt;em&gt;p&lt;/em&gt; or &lt;em&gt;a&lt;/em&gt;, and if it’s an &lt;em&gt;a&lt;/em&gt;, then the only allowed attributes are &lt;em&gt;href&lt;/em&gt; and &lt;em&gt;target&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s a very simple schema that of course doesn’t matches what you can do in HTML5, but remember that it’s a prototype aimed at showing off the amazing capabilities of Groovy 2.1.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To use it, you can do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    @CompileStatic
    void test() { // using a method to ensure that the builder will be statically compiled!
        def out = new ByteArrayOutputStream()
        def builder = new Builder3(out)
        builder.html {
            body {
                p &apos;Hello, Groovy!&apos;
            }
        }
        println out.toString()
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What we’re doing here is creating a builder inside a statically compiled portion of code (so that you can make sure that the builder usage is indeed statically compiled). If you run this code, it will show:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    Hello, Groovy!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But what is really interesting is showing what would happen if you use a wrong tag:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    @CompileStatic
    void test() { // using a method to ensure that the builder will be statically compiled!
        def out = new ByteArrayOutputStream()
        def builder = new Builder3(out)
        builder.html {
            bodyp { // compile-time error!
                p &apos;Hello, Groovy!&apos;
            }
        }
        println out.toString()
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, Groovy will fail at compile-time!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;    Groovyc: [Static type checking] - Cannot find matching method groovyx.transform.StaticMarkupBuilderTest#bodyp(groovy.lang.Closure). Please check if the declared type is right and if the method exists.
    Groovyc: [Static type checking] - Cannot find matching method groovyx.transform.StaticMarkupBuilderTest#p(java.lang.String). Please check if the declared type is right and if the method exists.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Of course, the error message can be improved (there are ways to do this), but what is interesting is that you really fail before the test gets executed!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_behind_the_magic&quot;&gt;Behind the magic&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To acheive this first example, there are two things in action:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a meta-annotation, called &lt;em&gt;@StaticMarkupBuilder&lt;/em&gt; that will expand itself into &lt;em&gt;@CompileStatic&lt;/em&gt; and &lt;em&gt;StaticMarkupBuilderGenerator&lt;/em&gt;: this way, using a single annotation, I am saying that the builder will be statically compiled without having to use @CompileStatic explicitely. The second annotation is an AST transformation:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an AST transformation that transforms the schema definition into a set of inner-classes, close to what the documentation says&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The AST transformation is very powerful. Say you have this schema:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    static schema = {
        html {}
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the AST transformation will create an inner class called &lt;em&gt;HTMLBuilder$HtmlTag&lt;/em&gt;, then also create, in the &lt;em&gt;HTMLBuilder class&lt;/em&gt;, a method which name is &lt;em&gt;html&lt;/em&gt; and uses a closure… Of course, it will add the &lt;em&gt;@DelegatesTo&lt;/em&gt; annotation transparently, so the generated method signature will look like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    void html(@DelegatesTo(HTMLBuilder$HtmlTag) Closure body) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For sub-tags, the principle is the same, but instead of generating the method in the HTMLBuilder class, it is added to the appropriate inner tag class… Of course, the AST transform does a bit more work:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;make the builder and each generated inner class extend a base class (&lt;em&gt;AbstractTag&lt;/em&gt;), this class defining how a tag should be rendered.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;generate methods for string only arguments (&lt;em&gt;p `text&apos;&lt;/em&gt;) or empty tags&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;generate a method for tags accepting attributes&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The latter is very important as it will help us demonstrate how we can also check that when the builder is used, the attributes being used are checked against a list of valid tags.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_the_attribute_checking_problem&quot;&gt;The attribute checking problem&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, we have an interesting problem: our schema allows us to say that the &lt;em&gt;a&lt;/em&gt; tag only accepts &lt;em&gt;href&lt;/em&gt; and &lt;em&gt;target&lt;/em&gt; attributes. But can we prevent the user from using other attributes at &lt;strong&gt;compile-time?&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;    builder {
        ...
        a(notGood:&apos;invalid attribute&apos;) { out &amp;lt;&amp;lt; &apos;Link text&apos; }
    }&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s see what happens if we don’t perform additional magic. When the builder is checked by the type checker, it will find a method named &lt;em&gt;a&lt;/em&gt;, which accepts a map and a closure as arguments. This method exists, so it passes compilation. This is bad, because we wanted a compile-time error here. We could have, when we generated the builder class, added a check into the &lt;em&gt;a&lt;/em&gt; method body that verifies that the map keys are in the authorized list, but it’s a runtime check and here we want a compile-time one…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So we have a new challenge:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;how to make the authorized attributes list known when the builder usage is compiled?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;how to make the static compiler &lt;strong&gt;check&lt;/strong&gt; that the user only picks attributes from that list&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For the first part, my choice was to add an annotation in the map parameter of the generated method:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    void a(@CheckedAttributes([&apos;href&apos;,&apos;target&apos;]) Map attributes, @DelegatesTo(...) Closure code) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alright, so now we have the information available at runtime, when the compiler will select this method, the method will have an annotation that we can reflect to retrieve the list of attributes… Still, the compiler won’t use that information, so we’re doomed, right?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Not really, because Groovy 2.1 includes &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Type+checking+extensions&quot;&gt;type checking extensions&lt;/a&gt;. A type checking extension will allow us to plug into the type checking system and perform additional checks that the compiler normally doesn’t do. Here, if it chooses this method, we will ask it to check the annotation and check that the actual arguments, those provided by the user, are using keys allowed by the builder!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code of this type checking extension can be found &lt;a href=&quot;https://bit.ly/Yryqb7&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;We’re almost done! The only problem with this solution is that one has to annotate every method that uses our builder with @CompileStatic(extension=’groovyx/transform/StaticBuilderExtension.groovy’). This is not as cool as seeing the extension being automatically applied…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect3&quot;&gt;
&lt;h4 id=&quot;_global_ast_transformations_to_the_rescue&quot;&gt;Global AST transformations to the rescue&lt;/h4&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There’s one solution to this. We will use a global AST transformation here. Unlike local AST transformations that are triggered by seeing an annotation in the code, global AST transformations are automatically loaded by the compiler and applied to every class being compiled. Thanks to this feature, we will be able to scan classes being compiled and if we find something annotated with @CompileStatic, then change it to @CompileStatic(extensions=’…’). That’s all!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code for such an annotation can be found &lt;a href=&quot;https://bit.ly/UfjmjQ&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You must remember that using global AST transformations have a significant impact on compilation times, since they are applied on every class, so always make sure you don’t use unnecessary transforms.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The main focus of this blog post wasn’t to describe in details how the AST transformation works, but rather show you how a smart combination of the features of Groovy 2.1 can allow you to perform tasks that would seem impossible, like type checking at compile-time the usage of a builder, statically compiling the code and eventually, performing checks on things that are normally unchecked by the compiler (arguments of a call).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the end, this example is not complete, of course:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the definition of the schema is insufficient (what about tags that allow arbitrary tags, …)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;allowText attribute isn’t used yet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the error messages can be improved (yes, it is possible to replace them with tags!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the API can be improved for more fluency&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But what is more important is that using such techniques, I am pretty sure that someone even crazier than me could write a more complete implementation that would accept, say… a real schema (think of xsd)!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Using Groovy to play with invokedynamic</title>
      <link>https://melix.github.io/blog//2013/01/31/using_groovy_to_play_with.html</link>
      <pubDate>Thu, 31 Jan 2013 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2013/01/31/using_groovy_to_play_with.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_invokedynamic_and_groovy_2&quot;&gt;InvokeDynamic and Groovy 2&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JVM language implementors, especially those working on dynamic languages like Groovy, welcome the arrival of invokedynamic in Java 7. InvokeDynamic is a new JVM instruction that was introduced to make our life easier. While this is only partially true, because we have to maintain backwards compatibility including older JVMs (Groovy still runs with JDK 1.5, for example), using invokedynamic to implement a dynamic language on the JVM is undoubtfully the way to go.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy 2.0 came with initial support for invokedynamic and the recently released Groovy 2.1.0 pushes support one step further by completing the implementation (in Groovy 2.1, if you compile code with invokedynamic support, the call site caching technique that regular Groovy uses to make dynamic calls faster is removed). What invokedynamic brings to Groovy 2.1 is basically improved performance. One has to know that talking about performance is always polemical and invokedynamic performance is even more difficult, because from one JVM version to another, you can have significantly different results. The JVM is still not perfectly optimized for invokedynamic. However, you may know that Java 8 will introduce lambdas to the language and the implementation of such a feature heavily relies on invokedynamic, so the JVM implementors are doomed to improve performance of invokedynamic!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a reminder, people wanting to test a Groovy runtime that uses invokedynamic have two things to do:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;use the &lt;em&gt;groovy-indy&lt;/em&gt; jar which includes support for invokedynamic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compile classes with the -indy flag&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you try to compile Groovy classes with -indy and the ``normal&apos;&apos; jar, you would have an error saying that indy is not supported, but if you compile a Groovy class using the indy jar &lt;em&gt;without&lt;/em&gt; activating the -indy flag, then classes would be compiled with call site caching instead of invokedynamic. While this might be suprising, there are good reasons for that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;invokedynamic support classes are only available in JDK 1.7+. That alone wouldn’t be a big deal as we could have worked around using stubs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the Groovy core classes are, sometimes, written in Groovy, so we use a ``bootstrap&apos;&apos; compiler to compile Groovy classes. In the -indy jar, core Groovy classes written in Groovy are compiled with invokedynamic, not call site caching. Therefore, we produce JDK 1.7+ bytecode only. Since Groovy is compatible with JDK 1.5, if we activated indy for all, you would have had incompatible classes for older JVMs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this blog post, however, I will &lt;strong&gt;not&lt;/strong&gt; talk about how Groovy 2 uses invokedynamic, but rather how you can use Groovy to test invokedynamic by yourself and start playing with the API without too much hassle.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_using_groovy_as_a_sandbox_for_invokedynamic&quot;&gt;Using Groovy as a sandbox for invokedynamic&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_the_bytecode_ast_transformation&quot;&gt;The @Bytecode AST transformation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Two years ago already, I released a new AST transformation for Groovy called the &lt;a href=&quot;https://www.jroller.com/melix/entry/groovy_bytecode_ast_transformation_released&quot;&gt;@Bytecode transformation&lt;/a&gt;. Basically, the idea was that if you thought you were smarter than the compiler, you could write bytecode as a method body had have the compiler write it. Started as a joke, some people found a lot of interested in it (some others thought I opened the box of Pandora) but my idea has always been that it was an amazing tool for teaching.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What I’m going to show you, here, is an extension of the &lt;a href=&quot;https://www.jroller.com/melix/entry/groovy_bytecode_ast_transformation_released&quot;&gt;@Bytecode transformation&lt;/a&gt; that supports the invokedynamic instruction. The main reason to use this annotation is that there is &lt;strong&gt;no way of generating invokedynamic instructions&lt;/strong&gt; using regular Java code. The only way to do this is to use a library like ASM. However, the ASM library is not easy to handle and it’s a pity that you have to spend time on bytecode generation tools just to be able to test invokedynamic. With the &lt;a href=&quot;https://www.jroller.com/melix/entry/groovy_bytecode_ast_transformation_released&quot;&gt;@Bytecode transformation&lt;/a&gt;, you now have a way of testing bytecode that makes use of invokedynamic very easily.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_setting_up&quot;&gt;Setting up&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, support for invokedynamic in &lt;a href=&quot;https://www.jroller.com/melix/entry/groovy_bytecode_ast_transformation_released&quot;&gt;@Bytecode&lt;/a&gt; is still experimental. You’ll have to build the jar by yourself, but don’t worry, it’s very easy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ git clone https://github.com/melix/groovy-bytecode-ast.git
$ cd groovy-bytecode-ast
$ ./gradlew jar&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you already have Gradle 1.4 installed, the build should only take a few seconds, otherwise Gradle will be downloaded for you.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, we’re going to create a Groovy project with a simple script that we’re going to run with invokedynamic. Althought this is not mandatory, I strongly suggest you to use the Gradle wrapper (which avoids installing Gradle everywhere), so we’ll just take advantage of the fact that the bytecode transformation is built with the wrapper to create a new project without having to install Gradle 1.4!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ cd ..
$ mkdir bytecodetest; cd bytecodetest
$ cp -Rp ../groovy-bytecode-ast/gradle* .&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here we’ve just copied the Gradle wrapper into a empty project, now we’re going to populate it. Open your favorite editor and paste the following code in a &lt;em&gt;build.gradle&lt;/em&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;apply plugin: &apos;groovy&apos;
apply plugin:&apos;application&apos;

repositories {
    mavenCentral()
}

dependencies {
    compile &apos;org.codehaus.groovy:groovy-all:2.1.0:indy&apos;
    compile fileTree(dir: &apos;lib&apos;, include: &apos;*.jar&apos;)
}

sourceCompatibility = 1.7
targetCompatibility = 1.7

[compileGroovy.groovyOptions,compileTestGroovy.groovyOptions]*.with {
    fork = true
    useAnt = true
    optimizationOptions = [ indy: true, &apos;int&apos;: false]
    encoding = &apos;UTF-8&apos;
}

mainClassName = &apos;Main&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What does this build file do? Basically, we’re using the Groovy plugin to compile Groovy files, including the &lt;code&gt;indy&apos;&apos; version of Groovy 2.1.0 (note the `indy&apos; classifier in the dependency and the fact we’re using the -all version of Groovy as it’s the only one compatible with @Bytecode) and configuring compilation so that it makes use of invokedynamic. The &lt;/code&gt;application&apos;&apos; plugin will allow us to run our script directly from Gradle once it’s compiled. For that, we’re just using a ``Main&apos;&apos; class.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last step is to copy the @Bytecode jar into the ``lib&apos;&apos; directory of your project:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ mkdir -p src/main/groovy
$ mkdir lib
$ cp ../groovy-bytecode-ast/build/libs/*.jar lib&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now we’re ready to create our first script! Create the src/main/groovy/Main.groovy file with the following content:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;println &apos;Hello, indy Groovy!&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Run the build:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ gradlew run
:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:run
Hello, indy Groovy!

BUILD SUCCESSFUL

Total time: 5.291 secs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Congratulations! At this point, you have generated a Groovy script which does compile using the invokedynamic version of Groovy. You can verify that it’s the case dumping the generated bytecode:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ javap -v build/classes/main/Main.class
public java.lang.Object run();
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: ldc           #55                 // String Hello, indy Groovy!
         3: invokedynamic #61,  0             // InvokeDynamic #1:invoke:(LMain;Ljava/lang/String;)Ljava/lang/Object;
         8: areturn

[...]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Excellent! Now, I said that our focus wasn’t testing Groovy with invokedynamic, but rather the opposite: testing &lt;em&gt;invokedynamic using Groovy&lt;/em&gt;. For this, what we would like to do is generating a method which introduces an invokedynamic call and wire the target method by ourselves. For example, take this code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;int bar() { 666 }

int foo() { bar() }

10.times {
   println foo()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;the foo() just delegates to ``bar&apos;&apos;. Now, instead of letting Groovy generate the bytecode for us, we want to generate the invokedynamic instruction by ourselves, then write the bootstrap method that will hardwire the link between bar() and foo().&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, we need a bootstrap method. The role of this method is, when an invokedynamic instruction is found, to setup the &lt;em&gt;callsite&lt;/em&gt;, that is to say create a link between a method call in bytecode and an actual target method being executed. That is to say that with invokedynamic, the relation between a call site and the method that will effectively be called is done at &lt;em&gt;runtime&lt;/em&gt;, not compile time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public static CallSite bootstrap(Lookup lookup, String callType, MethodType type) {
    new ConstantCallSite(lookup.findVirtual(Main, &apos;bar&apos;, MethodType.methodType(int)))
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, we’re creating a &lt;em&gt;constant call site&lt;/em&gt;, which means that once a target method is chosen, it will &lt;strong&gt;never&lt;/strong&gt; change for this call site. We’re linking our call site to a virtual method on the Main class, called `bar&apos; and returning an `int&apos;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, instead of letting Groovy do the job, let’s generate the method body by ourselves, so replace the foo() method with the following code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@Bytecode
int foo() {
    aload 0
    invokedynamic &apos;experiment&apos;, &apos;(LMain;)I&apos;, [H_INVOKESTATIC, &apos;Main&apos;, &apos;bootstrap&apos;, [CallSite, Lookup, String, MethodType]]
    ireturn
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Uh! That’s bytecode! Yes, and actually, it also hides all the complexity of the ASM library thanks to a nice Groovy DSL. The first instruction, &lt;em&gt;aload 0&lt;/em&gt; just loads the receiver on stack, that is to say &lt;em&gt;``this&apos;&apos;&lt;/em&gt;. The second instruction is our method call, the one we want to be linked to bar() and eventually, &lt;em&gt;ireturn&lt;/em&gt; takes the result of the call and returns it as an int.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s explain a bit what are the arguments of the invokedynamic method call. The first one is a label. You can put whatever you want in this, as long as it helps you. It’s often interesting if you have to debug your code, but it can also contain information that you want to have at hand when you will select the target method. The second one is the signature of the method you will call. Here, we say it’s a method on Main that returns an int. The last argument is a method handle to the bootstrap method. We’re saying that it’s a static method (INVOKESTATIC) found on the `Main&apos; class, named `bootstrap&apos; and accepting the arguments of types [CallSite, Lookup, String, MethodType]. Invoke dynamic supports more arguments for the bootstrap method, but it’s not discussed here. Putting it altogether:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovyx.ast.bytecode.Bytecode
import java.lang.invoke.*;
import java.lang.invoke.MethodHandles.Lookup;
import static groovyjarjarasm.asm.Opcodes.*
import static java.lang.invoke.MethodHandles.*

public static CallSite bootstrap(Lookup lookup, String callType, MethodType type) {
    new ConstantCallSite(lookup.findVirtual(Main, &apos;bar&apos;, MethodType.methodType(int)))
}

int bar() { 666 }

@Bytecode
int foo() {
    aload 0
    invokedynamic &apos;experiment&apos;, &apos;(LMain;)I&apos;, [H_INVOKESTATIC, &apos;Main&apos;, &apos;bootstrap&apos;, [CallSite, Lookup, String, MethodType]]
    ireturn
}

10.times {
    println foo() // prints 666
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s run it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ ./gradlew run
:run
666
666
666
666
666
666
666
666
666
666

BUILD SUCCESSFUL

Total time: 5.762 secs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And we did it! The link between the invokedynamic call site and our bar() method is dynamic, handled by our bootstrap method. To convince yourself, let’s just add a new method called baz():&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;int baz() { 123 }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And now, replace, in the boostrap method, `bar&apos; with `baz&apos;. Run the build again, and see what happens:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;$ ./gradlew run
:run
123
123
123
123
123
123
123
123
123
123

BUILD SUCCESSFUL

Total time: 5.693 secs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Easy? Now you’re ready to play with the invokedynamic API. For example, our next challenge was to call bar() and baz() alternatively. For that, your friend is going to be the MutableCallSite class, instead of ConstantCallSite. The difference between the two is that a MutableCallSite allows the target method handle to be changed over time. Here’s our code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.transform.CompileStatic
import groovyx.ast.bytecode.Bytecode
import java.lang.invoke.*;
import java.lang.invoke.MethodHandles.Lookup;
import static groovyjarjarasm.asm.Opcodes.*
import static java.lang.invoke.MethodHandles.*

public static MethodHandle findMethod(Lookup lookup, String name) {
    lookup.findVirtual(Main, name, MethodType.methodType(int))
}

public static CallSite bootstrap(Lookup lookup, String callType, MethodType type) {
    def (bar,baz) = [&apos;bar&apos;,&apos;baz&apos;].collect { findMethod(lookup, it) }
    def callsite = new ConstantCallSite(
            insertArguments(
                    lookup.findVirtual(Main, &apos;selectAndCall&apos;,
                            MethodType.methodType(Object, MutableCallSite, MethodHandle, MethodHandle))
                    , 1, new MutableCallSite(type), bar, baz).asType(type)
    )
    callsite
}

@CompileStatic
public def selectAndCall(MutableCallSite callSite, MethodHandle bar, MethodHandle baz) {
    callSite.with {
        target = (target.is(bar))?baz:bar;
        dynamicInvoker().invokeWithArguments(this)
    }
}

int bar() { 666 }
int baz() { 123 }

@Bytecode
int foo() {
    aload 0
    invokedynamic &apos;experiment&apos;, &apos;(LMain;)I&apos;, [H_INVOKESTATIC, &apos;Main&apos;, &apos;bootstrap&apos;, [CallSite, Lookup, String, MethodType]]
    ireturn
}

10.times {
    println foo() // prints 666 and 123 alternatively
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now run this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;./gradlew run
:run
666
123
666
123
666
123
666
123
666
123

BUILD SUCCESSFUL

Total time: 6.002 secs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s explain a bit what we did… Calling a different method each time requires us to change the target handle. However, the bootstrap method is only called &lt;strong&gt;once&lt;/strong&gt;. The trick, here, is to create a handle to a new method, here &lt;em&gt;selectAndCall&lt;/em&gt;, that takes our &lt;em&gt;MutableCallSite&lt;/em&gt; as an argument. Then, we create a &lt;em&gt;ConstantCallSite&lt;/em&gt; for which the target method is this method with the first argument &lt;em&gt;bound&lt;/em&gt; to our mutable call site. This means that instead of calling bar() or baz() directly, we’ll be calling selectAndCall which will change the target method &lt;em&gt;then&lt;/em&gt; call the bar() or baz() method.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, we’ve explained to you how you can leverage Groovy to test the invokedynamic API by yourself. I spent several months working on static type checking and static compilation for Groovy, without finding too much time to work with invoke dynamic. The next major version of Groovy should come with a new MOP (meta-object protocol) that heavily relies on the invokedynamic API, so this ``tool&apos;&apos; is also a good way for me to learn the API and play with it very easily. I hope this will be useful for you too!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy&amp;amp;Grails eXchange 2012, type checking and upcoming conferences</title>
      <link>https://melix.github.io/blog//2012/12/19/groovy_grails_exchange_2012_type.html</link>
      <pubDate>Wed, 19 Dec 2012 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2012/12/19/groovy_grails_exchange_2012_type.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_long_time_no_see&quot;&gt;Long time no see!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s a long time since I last blogged. I’ve been quite busy of course, but it doesn’t give me a good reason not to maintain this blog!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_groovygrails_exchange_2012&quot;&gt;The Groovy&amp;amp;Grails eXchange 2012&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last week, I spoke at the &lt;a href=&quot;https://skillsmatter.com/podcast/groovy-grails/type-checking-your-dsls&quot;&gt;Groovy&amp;amp;Grails eXchange 2012&lt;/a&gt;. It was a really pleasant experience and I wanted to share some feelings with you.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_static_guy&quot;&gt;The ``static&apos;&apos; guy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There is something very funny when I meet people now. One or two years ago, people knowing my name were just a few, focused, guys on the mailing list. Now, with the work I’ve done in Groovy 2, that is to say &lt;em&gt;static type checking&lt;/em&gt; and &lt;em&gt;static compilation&lt;/em&gt;, more and more people recognize me and even those who knew me before start to think of me as the ``static guy&apos;&apos;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The truth is that while it’s correct that my main focus was to develop those features and that I really enjoy it, I spent a lot of time working with Groovy before, and advocating its dynamic nature to my coworkers. The dynamic nature of the language helped us a lot and it’s definitely the main focus of the language. This means that in the dynamic vs static language war, I’m in the middle camp: I like both!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This directly drives me to the most surprising talk given at the &lt;a href=&quot;https://skillsmatter.com/event/groovy-grails/groovy-grails-exchange-2012&quot;&gt;Groovy&amp;amp;Grails eXchange&lt;/a&gt;, I mean &lt;a href=&quot;https://skillsmatter.com/podcast/groovy-grails/why-groovy-when-java-8-or-scala-or&quot;&gt;&lt;code&gt;Why Groovy when Java 8 or Scala or…&apos;&apos;&lt;/a&gt; by Russel Winder. When I say surprising, I mean that it’s not often that you can hear &lt;/code&gt;War Pigs&apos;&apos; from Black Sabbath before the talk begins, and it’s not often either that in a Groovy conference, a speaker tries to demonstrate that Groovy is no longer necessary. At least, he tried to, because knowing him as one of the best Groovy advocates in town, I was just wondering all the short 45 minutes session along, when turnaround would occur. It did not. Maybe because Russel expected the session to last 1 hour, but even with 15 more minutes, I’m not convinced that he would, because if I understood him well, he wanted by this talk to conduce the Groovy community to be more active in the JVM community in general, by proving by the fact that Groovy is a major language, not just a poor substitute to Java 8.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I &lt;em&gt;think&lt;/em&gt; I’m not too far from the truth when I read this very funny comment about me in his &lt;a href=&quot;https://www.russel.org.uk/blog/2012-12-18-19-57&quot;&gt;blog post&lt;/a&gt;: &lt;em&gt;Cédric Champeau the person driving the static type checking and compilation was in the audience and I survived. Perhaps I wasn’t contentious enough.&lt;/em&gt;. I’m sorry if I disappointed you, Russel, but as I’m not in particular the ``static guy&apos;&apos; people think I am and that I have a very clear idea of what static compilation in Groovy is good for, I think it makes it difficult to make me unconfortable on the subject. In fact, I’m most worried about what people would think of this talk just reading the slides! Another thing, maybe, is that humour and cultural references in this talk were very british centered (that makes sense, we were in London after all) and that it was sometimes difficult to follow for me.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_static_type_checking_for_groovy&quot;&gt;Static type checking for Groovy&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let me explain again why we introduced static type checking and static compilation in Groovy:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java scripting: (which has absolutely no relation to &lt;em&gt;Javascript&lt;/em&gt;). A lot of people use Groovy as a Java scripting language. They do not use dynamic features of Groovy, and they are often disappointed when the compiler doesn’t offer the same kind of feedback as the Java compiler.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovy as a better Java: Groovy syntax is more concise, Groovy has closures, learning curve is close to zero. Ah, but Groovy is a dynamic language. Period. @TypeChecked to the rescue!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance. You always have to be careful here, because as I always explain, Groovy is not slow (anymore). It even perfoms really good when you think of all the wonders it does before invoking methods. But in some situations, it is significantly slower than Java. For those cases, you can use @CompileStatic and have generated bytecode very close if not equal to what Java produces, so acheive the same level of performance.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What is interesting regarding performance is what Russel said in his talk: Java 8 will have lambdas, type checked lambdas (and using the new collections APIs the type checked syntax can even be more concise than the Groovy one, that’s a problem we must address) and for it, it makes use of the invoke dynamic feature that was introduced in Java 7. As you know, Groovy 2 introduced usage of invoke dynamic too, and Groovy 2.1 pushes it further enough that performance of dynamic Groovy is close to what Java offers (as always, be careful with figures, even more when talking about invokedynamic because from one VM to another you can have &lt;strong&gt;very&lt;/strong&gt; different results). But that’s what we hoped from day 1 when adding invoke dynamic support to Groovy: we seriously hope that performance of dynamic languages, and here Groovy, will become close to the performance of static languages. So if performance is close to Java, why did we introduce static compilation in the same version as invoke dynamic? There are various reasons for that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;unfortunately, people will not use Java 8 in production before years. Java 7 in production is still rare, most people are stuck with Java 6. We had to offer performance for those people too.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type checking: as explained before, even if you use a dynamic language, some people just &lt;strong&gt;want&lt;/strong&gt; compilation errors&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;enforced semantics: statically compiled code is immune to monkey patching. Any code compiled with invoke dynamic support will have the same behaviour as dynamic groovy, so will go though the meta-object protocol. This is not a problem, this is what we want and the good thing is that indy (invoke dynamic) makes it fast, but it can be a problem for framework creators, for example, that do not want their code to be subject to metaclass changes in a third party library.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Russel’s talk echoed to the last talk from day 1, which was an open discussion with the Groovy community. One of the covered subjects was why would people use static type checking or static compilation for Groovy. There were a lot of interesting comments but one of them shocked me: developers were saying that static type checking wasn’t necessary because you write unit tests. Ok, let me be very clear on the subject: I’m not against test-driven development (though I usually prefer writing unit tests as I implement things), but I seriously think that focusing on unit tests is a very big error:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;static type checking is about catching errors &lt;em&gt;early&lt;/em&gt;, without having to &lt;em&gt;run&lt;/em&gt; code. This is very important to understand&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;people do not write tests, and if they do, it’s always not enough. If you do, you can only write tests for what you think of. Just as well as 100% code coverage doesn’t mean no bugs, thousands of unit tests doesn’t guarantee you’re covering all cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DSLs: Groovy is a platform of choice for implementing DSLs. The thing is that a lot of DSLs are not aimed at developers. They are often aimed at people that know business rules and can focus on some formalism to describe them. Those people are not developers and you cannot expect them to write unit tests. That doesn’t mean we can’t do anything for them, and that’s also what my talk was about&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To be short, Groovy puts itself in the middle of the dynamic vs static war for very good reasons. One of them is choice. I like to have the choice to use the best strategy for my needs. If it’s dynamic code, let’s do it. If it’s static code, do it too. If you absolutely want type checking, you can, and if you want to use dynamic Groovy and still be able to throw errors at compile time for people using your DSL, now you can too… Because if you ever want to compare Groovy with Java 8, never ever forget that Groovy is more than statically compiled Groovy compared to Java 8. It offers both runtime and compile-time programming which makes it unavoidable if you want to implement a DSL on the JVM…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_static_type_checking_for_dsls&quot;&gt;Static type checking for DSLs&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;GGX was the first conference where I talked about a new feature in Groovy 2.1, which is ``customizable&apos;&apos; type checking. The idea is to help the type checker where it fails, because you know more about your code, what it does, how it is implemented than it does. This allows very nice features, like the ability to throw errors at compile time where Groovy would normally fail at runtime, but using DSLs, independently of their implementation. This is in particular important for people that implement DSLs using dynamic features of the language, because the type checker is obviously totally lost in that situation. Having the ability to check a user script at compile time, report errors before it goes in production is a big win here. You can even have the compiler be smarter than Java (or another statically compiled language) is given your domain.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The talk was rather technical and dealing with such a subject in only 45 minutes was a challenge (that I only half acheived) but I had good feedback. For those who are interested in the subject and missed this talk, you can still attend my session at &lt;a href=&quot;https://greach.es/&quot;&gt;the Greach conference&lt;/a&gt; in Madrid in the end of January. I hope I’ll be able to do it at GR8Conf in an extended version in May too. Of course, you can still watch the recorded session online.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think this is a very powerful feature that opens a lot of new capabilities just like adding AST transformations to the language drove Groovy to a superior level. I’m eager to see what people will be able to do with it, even if it requires, that’s true, some technical skills, in particular some knowledge about the Groovy AST (abstract syntax tree). For people who are used to writing AST transforms, that shouldn’t be much a problem.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_meeting_the_community&quot;&gt;Meeting the community&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Talking at conferences is always the best way to meet the community and gather feedback and new ideas from actual users. We are not, as Groovy or Grails committers, super heroes. I’m always amazed to see what users manage to do with what we implement in the language and I tend to think you are the real super heroes. At GGX, once again, I was really impressed with what Spock offers, for example. The talk was given by &lt;a href=&quot;https://freeside.co/&quot;&gt;Rob Fletcher&lt;/a&gt; who also gave another talk about Grails for Hipsters. Both of his talks were so attended that at this point, the conference could have been named ``The Rob Fletcher eXchange&apos;&apos;. If you want someone to demonstrate the superiority of dynamic languages over static ones, he’s your man.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Oh wait, did I say dynamic? ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last word as a special thanks to &lt;a href=&quot;https://www.cacoethes.co.uk/blog/&quot;&gt;Peter Ledbrook&lt;/a&gt; who left VMware a few weeks ago. He did a lot for this GGX conference but more than that, he was the best Groovy/Grails advocate and we’ll definitely miss him!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>My Git tweaks for daily usage</title>
      <link>https://melix.github.io/blog//2012/07/25/my_git_tweaks_for_daily.html</link>
      <pubDate>Wed, 25 Jul 2012 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2012/07/25/my_git_tweaks_for_daily.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_few_tricks_for_daily_git_usage&quot;&gt;A few tricks for daily Git usage&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt; switched to Git for version control, and more recently to GitHub for hosting, I’ve had great pleasure working with this tool. In this post, I’ll just show you some basic tricks that I use on a daily basis.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_adding_the_git_branch_to_the_bash_prompt&quot;&gt;Adding the git branch to the Bash prompt&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My first tweak is to have my bash prompt show me the current branch I’m working on. This is very handy. I borrowed the setup from &lt;a href=&quot;https://pastebin.com/CLYTaS5A&quot;&gt;this pastebin&lt;/a&gt; but unfortunately, I can’t find the original author. Note that it also adds support for svn. Add the following to your &lt;em&gt;.bashrc&lt;/em&gt; file:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;#GIT
simple_git_branch() {
  git branch 2&amp;gt; /dev/null | sed -e &apos;/^[^*]/d&apos; -e &apos;s/* \(.*\)/\1/&apos;
}

parse_git_branch() {
  git branch 2&amp;gt; /dev/null | sed -e &apos;/^[^*]/d&apos; -e &apos;s/* \(.*\)/(git::\1)/&apos;
}
parse_svn_branch() {
  parse_svn_url | sed -e &apos;s#^&apos;&quot;$(parse_svn_repository_root)&quot;&apos;##g&apos; | awk -F / &apos;{print &quot;(svn::&quot;$1 &quot;/&quot; $2 &quot;)&quot;}&apos;
}
parse_svn_url() {
  svn info 2&amp;gt;/dev/null | grep -e &apos;^URL*&apos; | sed -e &apos;s#^URL: *\(.*\)#\1#g &apos;
}
parse_svn_repository_root() {
  svn info 2&amp;gt;/dev/null | grep -e &apos;^Repository Root:*&apos; | sed -e &apos;s#^Repository Root: *\(.*\)#\1\/#g &apos;
}
export PS1=&quot;\[\033[00m\]\u@\h\[\033[01;34m\] \w \[\033[31m\]\$(parse_git_branch)\$(parse_svn_branch) \[\033[00m\]$\[\033[00m\] &quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_some_aliases&quot;&gt;Some aliases&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;All those aliases must be added to your &lt;em&gt;.gitconfig&lt;/em&gt; file into the &lt;em&gt;[alias]&lt;/em&gt; section.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One thing I’m doing often with Groovy development is to fix some bug into a branch, then backport the fix to other branches. My preferred tool for this is &lt;em&gt;cherry-pick&lt;/em&gt;. Cherry picking a commit is really easy, but to make it even easier, I’m using an alias that shows me the hash of the last commit on a branch:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[alias]
 last = log --oneline -n 1&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then calling &lt;em&gt;git last&lt;/em&gt; will show me the hash of the commit to be cherry-picked. Another problem is that &lt;em&gt;git cherry-pick&lt;/em&gt; is a bit long to type, especially if you do this often, and &lt;em&gt;git cherry&lt;/em&gt; doesn’t get autocompleted when you press tab, so I’m using another alias for cherry-picking:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[alias]
 cp = cherry-pick&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are used to &lt;em&gt;svn&lt;/em&gt;, you also know that &lt;em&gt;co&lt;/em&gt; is an alias for &lt;em&gt;checkout&lt;/em&gt; so I’m adding this too:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[alias]
 co = checkout&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, here is a nice history view of commits:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[alias]
 hist = log --oneline --graph --decorate --all&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s all, those aliases are currently the only ones I’m using on a daily basis, but of course, I’m relatively new to git, so there are chances that new aliases will show up in the future!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Improved AST transformation testing in Groovy 2</title>
      <link>https://melix.github.io/blog//2012/07/12/improved_ast_transformation_testing_in.html</link>
      <pubDate>Thu, 12 Jul 2012 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2012/07/12/improved_ast_transformation_testing_in.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_structural_ast_testing&quot;&gt;Structural (AST) testing&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since Groovy 1.6, the language provides a very nice feature called &lt;a href=&quot;https://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations&quot;&gt;AST transformations&lt;/a&gt;. AST transformations allows you to hook into the compilation process in order to modify the internal representation of the source code at compile time. This internal representation, known as the Abstract Syntax Tree(AST) is a very powerful way to enhance the language or reduce verbosity of the code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The different releases of Groovy came with new AST transformations such as:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;@Log/@Log4j/@Slf4j&lt;/em&gt;: transparently adding a logger to your class&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;@ToString&lt;/em&gt;: Generating a nice &lt;em&gt;toString&lt;/em&gt; implementation for your class&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;@EqualsAndHashCode&lt;/em&gt;: Generating the famous &lt;em&gt;equals&lt;/em&gt; and &lt;em&gt;hashcode&lt;/em&gt; methods&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;@Canonical&lt;/em&gt;: Combining &lt;em&gt;@ToString&lt;/em&gt; and &lt;em&gt;@EqualsAndHashCode&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;@WithReadLock/@WithWriteLock&lt;/em&gt;: for guarding method bodies with read/write locks (reentrant locks)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;and many more!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Developing such AST transformations is very interesting but requires a deeper knowledge of the internal APIs of the Groovy language (specifically, the AST part). However, people who have developped such AST transformations know that testing them is a bit difficult:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The most useful tool is the &lt;em&gt;AST browser&lt;/em&gt; which can be found in the &lt;em&gt;Groovy Console&lt;/em&gt;. It allows you to ``browse&apos;&apos; the AST of the code which is in the console. This is very useful because it allows you to write the code you’d like to generate and see what AST structure you need to produce. Or you can use it the opposite way, looking for patterns of AST to recognize in order to transform them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Testing if the AST transform is successul can only be done externally, that is to say by testing that the effects of the transform are visible on a class. For example, testing the &lt;em&gt;@Log&lt;/em&gt; AST transform consists in applying the transform on a test class, then add calls to &lt;em&gt;log&lt;/em&gt; and see if they are successful.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;External testing is easy to do, but the main problem is that you no longer manipulate an AST: you manipulate classes which have already been generated. This is problematic for several reasons:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You can only test when your AST transform code is valid, that is to say that it doesn’t throw an error in the compilation process.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Groovy compilation process is separated into phases, and it is useful to add tests to check was exists in one phase, and what exists in another phase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can only check easily things that introduce/remove fields or methods. It’s impossible to test, for example, an AST transform which doesn’t touch the AST…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You cannot check for properties found in the AST&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The two last points were my major concern when I developped the type checker for Groovy 2. As you may know, the type checker is implemented in the form of an AST transformation which annotates the AST with node metadata. This node metadata is not visible in the AST browser and is of free form. In the case of the type checker, node metadata consists of type inference information. So, in that case, testing my AST transformation consisted of scripts with variables defined with certain types, and just checking that the compiler didn’t throw any error (or did throw an error). The problem is that you cannot check if the inferred type of a precise AST node is correct.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_improved_ast_transformation_testing&quot;&gt;Improved AST transformation testing&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_asttest&quot;&gt;@ASTTest&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For that reason, Groovy 2.0 introduces a new AST transformation which is precisely aimed at testing AST transformations! This AST transformation is named &lt;em&gt;ASTTest&lt;/em&gt; and allows you to execute assertions on the AST tree. Let’s take a simple example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;    for (int i in 1..n) {
        @ASTTest(phase=INSTRUCTION_SELECTION, value= {
            assert node.getNodeMetaData(DECLARATION_INFERRED_TYPE) == int_TYPE
        })
        def k = i
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This test is extracted from the type checker test suite. You can see:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;we’re annotating a declaration with &lt;em&gt;ASTTest&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we specify, as an annotation parameter, the compilation phase the test is expected to run&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;and we specify code which will be executed on the annotated AST node&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, &lt;em&gt;node&lt;/em&gt; in the closure refers to the annotated AST node, that is to say, here, a &lt;em&gt;DeclarationExpression&lt;/em&gt;. We’re calling &lt;em&gt;getNodeMetaData&lt;/em&gt; which is a method defined on any AST node which allows to retrieve the node metadata that we talked about earlier. Here, we want to retrieve the type of the variable which is inferred by the type checker. Last and important, we add an assert statement to check that this inferred type corresponds to an &lt;em&gt;int&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If the assertion fails, the unit test will fail. This is very important, because we now have a mean to test the AST itself. I said it was impossible before, but in fact, it was possible but it required a lot of trickery such custom classloaders and so on…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Groovy 2.0.0, &lt;em&gt;ASTTest&lt;/em&gt; does nothing more than this, but we have a problem: not every node in the AST can be annotated. We’re limited to what it is syntactically possible to annotate: classes, methods, types, packages, declarations, … If what you want to test is a node which doesn’t belong to that category, then you need to annotate a wrapping node (in most situations, a method) then ``browse&apos;&apos; manually to the node you want to test. For example, in the previous example, we could access the right hand side of the declaration expression using &lt;em&gt;node.rightExpression&lt;/em&gt; and perform assertions on that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, if you start from a method and try to access a particular node into the method body, I admit it is quite painful, because you have to check what is the exact AST tree which is generated by the compiler, then find a ``path&apos;&apos; to your node. And it is very easy to break this path just by adding a statement in the code, which makes the unit tests fragile.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_improving_asttest&quot;&gt;Improving @ASTTest&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For that reason, I wrote an utility class which will allow you to perform ``smart&apos;&apos; lookups in the AST tree. This helper class is not available in Groovy 2.0.0 but it is easy to add and I will probably introduce it in the next release(&lt;em&gt;edit:&lt;/em&gt; see &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY-5597&quot;&gt;GROOVY-5597&lt;/a&gt;): it is called &lt;em&gt;LabelFinder&lt;/em&gt;. The idea is that even if you cannot annotate everything in the code, it’s still very easy to add &lt;em&gt;labels&lt;/em&gt; to your code. Then, Groovy may be able to search for a particular label and return to you the list of AST nodes which are defined on such a label:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;void foo() {
    def x = 1
    x++
    forLoop:
    for (int i=0; i
Here, we added a forLoop label in the code, and we will use it as a lookup point for @ASTTest:

@ASTTest(phase=SEMANTIC_ANALYSIS, value= {
     lookup(node, &apos;forLoop&apos;).each {
        assert it instanceof ForStatement
     }
})
void foo() {
    def x = 1
    x++
    forLoop:
    for (int i=0; i
The major advantage of this technique is that you don&apos;t suffer the structural code syndrom anymore: the test is not fragile with regards to AST changes anymore. If you introduce
statements before the forLoop label, this won&apos;t change the result of the call to lookup. If you don&apos;t use such an utility, you would have to change, for example, the index
of a statement in a block...
In this example, I made use of a static import to reduce the verbosity of the test code. You may be interested in seeing the actual code of LabelFinder. It&apos;s actually quite simple:

public class LabelFinder extends ClassCodeVisitorSupport {


    public static List lookup(MethodNode node, String label) {
        LabelFinder finder = new LabelFinder(label, null)
        node.code.visit(finder)

        finder.targets
    }

    public static List lookup(ClassNode node, String label) {
        LabelFinder finder = new LabelFinder(label, null)
        node.methods*.code*.visit(finder)
        node.declaredConstructors*.code*.visit(finder)

        finder.targets
    }

    private final String label
    private final SourceUnit unit

    private List targets = new LinkedList();

    LabelFinder(final String label, final SourceUnit unit) {
        this.label = label
        this.unit = unit;
    }

    @Override
    protected SourceUnit getSourceUnit() {
        unit
    }

    @Override
    protected void visitStatement(final Statement statement) {
        super.visitStatement(statement)
        if (statement.statementLabel==label) targets &amp;lt;&amp;lt; statement
    }

    List getTargets() {
        return Collections.unmodifiableList(targets)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_enjoy&quot;&gt;Enjoy!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I hope you liked this little introduction to a simple yet powerful tool introduced in Groovy 2. In sincerely hope this will make the life of AST transformations developpers easier!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Gradle plugin for CloudFoundry now supports standalone applications</title>
      <link>https://melix.github.io/blog//2012/07/03/gradle_plugin_for_cloudfoundry_now.html</link>
      <pubDate>Tue, 3 Jul 2012 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2012/07/03/gradle_plugin_for_cloudfoundry_now.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_gradle_cf_plugin_upgraded_to_0_2&quot;&gt;gradle-cf-plugin upgraded to 0.2&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have just published a new version of the &lt;a href=&quot;https://www.gradle.org&quot;&gt;Gradle&lt;/a&gt; plugin for &lt;a href=&quot;&quot;&gt;CloudFoundry&lt;/a&gt;. The main change is that it supports standalone applications, meaning you will be able to push your applications to CloudFoundry all from Gradle.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To deploy a standalone application, you can do the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;buildscript {
       repositories {
         mavenCentral()
       }
       dependencies {
           classpath group: &apos;org.gradle.api.plugins&apos;, name: &apos;gradle-cf-plugin&apos;, version: &apos;0.2.0&apos;
       }
   }

   apply plugin: &apos;cloudfoundry&apos;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then add to your &lt;em&gt;build.gradle&lt;/em&gt; file a section describing your deployment settings (note the &lt;em&gt;standalone&lt;/em&gt; framework):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;cloudfoundry {
   target=&apos;https://api.vcap.me&apos;
   username = &apos;user-AT-domain-DOT-com&apos;
   password=&apos;foobar&apos;
   application = &apos;myapp&apos;
   framework = &apos;standalone&apos;
   applicationFramework=&apos;standalone&apos;
   runtime = &apos;java&apos;
   command = &quot;$name/bin/$name&quot;
   file = distZip.archivePath
   uris = [&apos;https://myurl.vcap.me&apos;]
   memory = 256
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you migrate your application from version 0.1.0 to 0.2.0 of the plugin, then you have to change the &lt;em&gt;warFile&lt;/em&gt; property to &lt;em&gt;file&lt;/em&gt;. Now, you are able to push your application to CloudFoundry using the &lt;em&gt;cf-push&lt;/em&gt; task:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;gradle cf-push&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that in future versions of the plugin, we will likely change the name of the tasks so that they follow the Gradle conventions (using, for example, &lt;em&gt;cfPush&lt;/em&gt; instead of &lt;em&gt;cf-push&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy 2.0 from an insider</title>
      <link>https://melix.github.io/blog//2012/06/29/groovy_2_0_from_an.html</link>
      <pubDate>Fri, 29 Jun 2012 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2012/06/29/groovy_2_0_from_an.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovy_2_0_is_has_landed&quot;&gt;Groovy 2.0 is has landed!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s with great pleasure that we released Groovy 2 yesterday. For me, this is a special release and some kind of achievement because this is the first one for which I had a large contribution (a bit selfish I admit, but well…). Before that release, I had contributed code, then became committer, but I didn’t have much time to give to the Groovy project. Now that I’m working full time on it, it’s a bit easier!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post, I will try to investigate some of the new features of Groovy 2 and provide you additional details that you won’t find in the announcement like some technical insight. There fore, it’s a good complement to the introduction that you can find on &lt;a href=&quot;https://bit.ly/LV5N25&quot;&gt;InfoQ&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_modularization&quot;&gt;Modularization&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_modules&quot;&gt;Modules&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is probably one of my favorite features of Groovy 2. In this version, we made a lot of effort to split Groovy into several modules. This effort, driven by Paul King and backed by a &lt;a href=&quot;https://docs.codehaus.org/display/GroovyJSR/GEP+9+-+Modularization&quot;&gt;Groovy Enhancement Proposal&lt;/a&gt; has introduced several major changes in the codebase:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A build which is now fully based on &lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Core Groovy only contains the minimal set of classes required to run the language&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Several &lt;em&gt;optional&lt;/em&gt; modules in their own source subtree&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;an &lt;em&gt;extension module&lt;/em&gt; mechanism has been put in place&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are dependencies between modules. Actually, if you look at the Gradle build, you would find a rather complicated dependency graph, but most of the complexity is just that we need to build a &lt;em&gt;minimal core&lt;/em&gt; of Groovy (written in Java) to build the full Groovy project itself. As for the modules, here is the current dependency graph (click for larger image):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jroller.com/melix/resource/images/deps.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/images/deps.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Each module is available as a Maven artifact, under the groupId &lt;em&gt;org.codehaus.groovy&lt;/em&gt; and an artifactId corresponding to the name on the schema. The core Groovy module is named &lt;em&gt;groovy&lt;/em&gt; (not &lt;em&gt;groovy-core&lt;/em&gt;) for compatibility with previous releases (you just need to upgrade the version number). We also provide a &lt;em&gt;groovy-all&lt;/em&gt; jar which bundles all those modules in a single jar, as well as packaging some dependencies into a separate package to avoid class loading issues (in particular with ASM which is used by a lot of frameworks, but in different versions). If you upgrade from a previous version of Groovy, there are only two possible paths: if you were using the &lt;em&gt;groovy-all&lt;/em&gt; jar, then just upgrade to the new &lt;em&gt;groovy-all&lt;/em&gt; version. If you were using &lt;em&gt;groovy.jar&lt;/em&gt;, then it is possible that some of the classes you were using have now moved into a module. In that case, include the module jar as a dependency.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s worth noting that Groovy 2.0.0 is just a &lt;em&gt;milestone&lt;/em&gt; in the modularization task: the following releases of Groovy will add new features, like the ability to add custom file extensions that actually &lt;em&gt;do something different&lt;/em&gt; (like transparently applying AST transformations).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_extension_modules&quot;&gt;Extension modules&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When I talked about modularization, I told you that this was one of my favorite features. Now, I’m going to explain why! Groovy is more than a language. It also provides a lot of helpful APIs to reduce code verbosity. For example, if you have the &lt;em&gt;java.io.File&lt;/em&gt; class in &lt;em&gt;Java&lt;/em&gt;, there is no &lt;em&gt;getText(String encoding)&lt;/em&gt; method on it which allows you to retrieve the contents of the file, although this is a quite common operation. Groovy adds this method onto the &lt;em&gt;File&lt;/em&gt; class. This is sometimes (incorrectly) called known &lt;em&gt;category methods&lt;/em&gt; or to be more correct_extension methods_. In previous versions of Groovy, most of those methods were defined in a class named &lt;em&gt;DefaultGroovyMethods&lt;/em&gt;. With modularization, we have exploded that class into multiple helper classes, but more importantly, we added the ability for you to &lt;strong&gt;add your custom extension methods!&lt;/strong&gt;. In the past, if you wanted to add a method named &lt;em&gt;foo&lt;/em&gt; on the &lt;em&gt;String&lt;/em&gt; class, there weren’t many options:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;write a &lt;em&gt;Category&lt;/em&gt; class, then &lt;em&gt;use&lt;/em&gt; it: while this is quite easy to do, it has major drawbacks. First, it is lexically scoped &lt;strong&gt;and&lt;/strong&gt; thread bound. This means that it is a dynamic feature, and that opening a &lt;em&gt;use&lt;/em&gt; block influences all Groovy code being executed until the block is closed, including method calls. In other words, category usage ``leaks&apos;&apos; into the current thread (which can have its own advantages but I don’t like side effects). Moreover, it cannot be statically checked (which is one of the major additions of Groovy 2). Additionally, categories are performance killers, as they imply disabling a lot of possible optimizations. I think you understand, now, that I really don’t like categories!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use a &lt;em&gt;metaclass&lt;/em&gt;: it is very easy to do, but once again, it’s a pure dynamic feature, so it cannot be statically checked. It also has the disadvantage of not being easily reusable, and eventually, you may still be in conflict with another part of the code replacing the metaclass (which would remove your changes). Unlike categories, metaclass changes are visible to every thread and have immediate effect on every Groovy class. This is why this feature is the perfect candidate for &lt;em&gt;monkey patching&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;write an &lt;em&gt;AST transformation&lt;/em&gt;: done at compile time, this would transform your &lt;em&gt;foo&lt;/em&gt; call into another call. This has the advantage of beeing done at compile time, also meaning that they can be statically checked (and compiled!), but writing AST transformations requires knowledge of (part of) the Groovy compiler infrastructure (specifically, the AST part). In general, unless you already have written AST transformations, this is much slower to develop than playing with a metaclass. It is also much harder to debug. But in the end, this is a very powerful feature and performance-wise, it is in general better than metaclass hacks. One important thing with AST transforms, though, is that they are selectively applied: you may choose on what classes they run, meaning that it’s not necessarily a global feature.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With Groovy 2, we provide a new way to write such extension methods, in a very friendly way: basically, you just need to write a support class that ``looks like&apos;&apos; DefaultGroovyMethods or Groovy categories. I will not repeat here how you can write such extension methods, but documentation can be found &lt;a href=&quot;https://docs.codehaus.org/display/GROOVY/Creating+an+extension+module&quot;&gt;here&lt;/a&gt;. This technique has many advantages:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;easy to write&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;easy to share (modules are jar files which may be included as a dependency)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;compatible with static type checking &lt;strong&gt;and&lt;/strong&gt; static compilation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is so easy to put in place that we already have, for example, an &lt;em&gt;extension module&lt;/em&gt; from &lt;a href=&quot;https://twitter.com/tim_yates&quot;&gt;Tim Yates&lt;/a&gt; adding &lt;a href=&quot;https://timyates.github.com/groovy-stream/&quot;&gt;generators to Groovy&lt;/a&gt;. Another interesting thing with the way extension modules are written is that many third-party libraries already use that kind of extension mechanism. Think of &lt;a href=&quot;https://commons.apache.org/lang/api-2.5/org/apache/commons/lang/StringUtils.html&quot;&gt;Apache Commons StringUtils class&lt;/a&gt; for example. Every method in that class is a static method taking a &lt;em&gt;String&lt;/em&gt; as the first parameter. With extension modules, this means that all you have to do is to write a module descriptor referencing that class to have those methods added directly on the &lt;em&gt;String&lt;/em&gt; class!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For advanced programmers, the extension module framework that have been added to Groovy allows you to register &lt;em&gt;MetaMethod_s to Groovy. This means that it not necessary for you to follow the static method way of doing extension methods: you could implement your own! Whatever technique you choose, you must be aware that just like _metaclass&lt;/em&gt; tricks, extension methods are global: you cannot choose on what lexical scope they apply. Once the hooks are installed, extension methods are there forever.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_static_type_checking_and_compilation&quot;&gt;Static type checking and compilation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_static_type_checking_in_a_dynamic_language&quot;&gt;Why static type checking in a dynamic language?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are various reasons why we wanted to add static type checking to the Groovy language. They are discussed in &lt;a href=&quot;https://bit.ly/LV5N25&quot;&gt;Guillaume Laforge’s article on InfoQ&lt;/a&gt; but the main reason is definitely that &lt;strong&gt;we want Groovy to be even easier to use by Java developers&lt;/strong&gt;. There has been a lot of FUD about Groovy performance and the fact that it is dynamically typed, but in the end, Groovy is among the fastest dynamic languages (if not the fastest) and performance problems are more often coming from I/O operations than from the language itself! Also, we must think about all developers: not everyone builds a Twitter… But for people coming from Java, the lack of static type checking was often a barrier preventing them from using Groovy. There are many things to say about dynamic vs static languages, but for people who are interested in evaluating productivity or ease of debugging, there are some interesting results in &lt;a href=&quot;https://www.cs.washington.edu/education/courses/cse590n/10au/hanenberg-oopsla2010.pdf&quot;&gt;this study from Stefan Hanenberg.&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Speaking of that, we often see (and we are really irritated by this) the quote from James Strachan, founder of the &lt;em&gt;Groovy&lt;/em&gt; language, promoted as a very good reason why not to choose Groovy (and its corrolate, prefer Scala over it): ``I can honestly say if someone had shown me the Programming Scala book by Martin Odersky, Lex Spoon &amp;amp; Bill Venners back in 2003 I’d probably have never created Groovy.&apos;&apos; I don’t know James personaly and I really respect his work and opinion and I joined the project well after but:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;James made this statement in 2009 after leaving the project in 2006 even before Groovy 1.0 was released. He is now also working on the Kotlin language. I don’t think that would mean that if Kotlin had existed back in 2003, Odersky wouldn’t have created Scala… or that James would drop Scala anyway. Different languages acheive different goals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If JPA existed in 2002, do you think Hibernate would have been created? Technology is innovation and languages are not different from any other piece of software in that case!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a &lt;strong&gt;lot&lt;/strong&gt; of improvements have been made on the language since then. I mean, you cannot honestly compare Groovy 1.0 with what Groovy 2.0 is. It’s now a mature, widely adopted language and reading such a quote should not prevent you from testing it by yourself.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;this is a personal comment, but definitely, I find Groovy &lt;strong&gt;much&lt;/strong&gt; more readable than Scala. It was easy to make Java developers use Groovy, it’s not so easy to write Scala, and it’s even more difficult to debug other people’s Scala code…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovy was never meant to replace Java. All we want is to make the life of developers easier and reintroduce &lt;em&gt;fun&lt;/em&gt; in programming.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One interesting thing to know is where I come from. Before working on Groovy for VMware, I was employed by a small French company named &lt;a href=&quot;https://www.lingway.com&quot;&gt;Lingway&lt;/a&gt; where I introduced the usage of Groovy in several projects. Groovy was used in many contexts, but one thing that is worth noting is that the audience was pretty large: from developers to linguists. Developers used Groovy as a Java scripting tool, sometimes as an ETL processor and linguists used it in the form of a DSL for natural language processing. In the end, we wrote a high performance natural language processor which performed text extraction, named entity recognition, part-of-speech tagging, … just using DSL rules written in Groovy. We had performance issues with Groovy, but in the end, they were all fixed by rewriting classes in Java. Of course, none of the rules were written in Java, so the engine was mostly written in Java, but rules, which are the core of the extraction system, are all written in Groovy, and performance is very good (and it’s using Groovy 1.8 by the way). However, it’s true that it was quite frustrating to rewrite classes in Java when they would have been much shorter and readable if written in Groovy. Moreover, none of those classes were using any of the dynamic features of the language…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Developers were Java developers. And some of them (who may recognize themselves reading this paper) were defintely not fans of dynamic typing. While I spent a lot of time advocating the advantages of Groovy over Java for readability and conciseness, in the end, if you end up using Groovy as a scripting language for Java and that you don’t use the dynamic features of the language, it is very legitimate to ask for static type checking, so that errors are catched early in the development process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_its_optional&quot;&gt;It’s optional!&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With Groovy 2, we want people to have &lt;strong&gt;choice&lt;/strong&gt;. Groovy is a very elegant language that removes most of the boilerplate of Java while staying very close to it, grammar-wise, hence very easy to learn. But it was definitely a problem for us to see people choosing other languages because of the lack of a type checker, although we think Groovy is much more readable than a lot of its competitors. Now, you will have the choice. You will have the choice to type check your code, and explicitely choose not to use the dynamic features of the language, and you will even have the choice to statically compile your code (with its own semantics). This adresses the two main issues we’ve talked about here: failing early in the development process thanks to static type checking, and adressing episodic performance issues by statically compiling your code.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_insider&quot;&gt;Insider&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Developing the static type checker was a very challenging task. I spent much less time on static compilation, which is an order of magnitude simpler than type checking. I learnt a lot doing this, and despite all the time spent in implementing that feature, I am pretty sure there are still bugs (in fact, I’m already aware of some), especially when it comes to generics. Oh man. Generics. I mean, I really like &lt;em&gt;using&lt;/em&gt; generics and the kind of type inference they offer, but algorithms are damn complex. Type inference with generics &lt;em&gt;is&lt;/em&gt; the real challenge. There were two problems that I had to face: first, the internal representation of generics in Groovy is not well suited for type inference, which makes algorithms unnecessary complex (complexity over complexity). Second problem was testing: although you think about a lot of cases, you only develop what you think of. We need testing and we need tests made by others. This is also why there were so many bug fixes in the RC phase: people tend to test the RC versions, not the betas, but this is life!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you’re interested in the internals, just be aware that the type checker is implemented as an AST transformation (yes!). So basically, it’s a (very) big transformation. The first step was to make it work, then make it right. Now, before making it fast (we didn’t talked about performance of the type checker itself, but it should be almost unnoticeable) I need to simplify code and, of course, fix the bugs!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_invoke_dynamic&quot;&gt;Invoke Dynamic&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A small word on invoke dynamic support in Groovy 2. We must congratulate Jochen Theodorou for that, because he spent a lot of time working on a feature which is hidden for most users. But his work is an important milestone for the future of Groovy, and while we will work on improving the performance of invoke dynamic in the 2.x versions of Groovy (as well as the JVM folks are going to improve performance of invokedynamic in the JVM itself because it will be at the core of the upcoming lambdas in JDK 8), Groovy 3 will probably be a language heavily relying on this feature.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_get_it_and_test_it&quot;&gt;Get it and test it!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but important, here are some links:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://bit.ly/LV5N25&quot;&gt;A detailed overview of Groovy 2 by Guillaume Laforge&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://groovy.codehaus.org/Download&quot;&gt;Download and give a try to Groovy 2!&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.dzone.com/links/groovy_20_released_with_static_type_checking_and.html&quot;&gt;Vote on DZone!&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Static compilation for Groovy poll results</title>
      <link>https://melix.github.io/blog//2012/01/29/static_compilation_for_groovy_poll.html</link>
      <pubDate>Sun, 29 Jan 2012 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2012/01/29/static_compilation_for_groovy_poll.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_static_compilation_or_no_static_compilation&quot;&gt;Static compilation or no static compilation?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my &lt;a href=&quot;https://www.jroller.com/melix/entry/static_type_checking_talk_from&quot;&gt;previous blog post&lt;/a&gt;, I published a link to the slides from my talk at the Paris Groovy and Grails User Group, where I presented the state of static type checking and compilation for Groovy 2.0. This talk was a unique occasion to retrieve feeback from the user community before we make any final decision about what should (or should not) be included in Groovy 2.0. Especially, we discussed about static compilation (there’s a consensus about static type checking, so I won’t talk about that here).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I decided to add two polls to my presentation and especially, I wanted the poll about &lt;strong&gt;why&lt;/strong&gt; people wanted static compilation to be answered &lt;strong&gt;before&lt;/strong&gt; I talked about the feature. This was important to me because I didn’t want the result to be biased by my talk. After two weeks, 42 persons have answered the polls. Nor me, nor Guillaume Laforge nor Jochen Theodorou answered the poll, once again not to bias the results. Here are the results for question 1:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://jroller.com/melix/resource/polls/why-static-compilation.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Again, the question was introduced before I talked about the feature and it’s a multiple choices question (you may choose several answers). What is interesting is that only 3 persons said they didn’t want static compilation, although on the development mailing list, people against static compilation were very vocal. If only 3 people do not need static compilation, this would mean that the others have a good opinion about why they need it, so the following figures are interesting too:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;performance&lt;/strong&gt; and &lt;strong&gt;type safety&lt;/strong&gt; are both at the same level and the highest number of answers (17). While performance was really to be expected, I didn’t expect &lt;em&gt;type safety&lt;/em&gt; so high, because basically, if you need type safety, the &lt;em&gt;@TypeChecked&lt;/em&gt; annotation is enough (you don’t need static compilation). However, this is only true if you don’t consider the monkey patching issues, where the behaviour of Groovy can be changed at runtime, leading to runtime type errors while the program was statically checked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I want a better Java&lt;/strong&gt; comes next, with 12 answers. I expected this one, because when we talked about the static compilation feature on the mailing list, we had an interesting discussion about why people use Groovy, and I was thinking a lot of people already used Groovy as a better Java, although the language wasn’t designed as a replacement but more as a companion to Java.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the next reason coming is that &lt;em&gt;people do not need the dynamic features&lt;/em&gt; of Groovy. This is interesting too, because it has to be linked to two different things. First, type safety, because as we already said, you can type check the program to ensure type safety (not needing static compilation) only if you can guarantee that nothing beyond the scope of the compiler (already compiled classes, third party libraries or frameworks) do no modify the behaviour of a program at runtime. Statically compiling the program disables dynamic features, so using static compilation you can &lt;em&gt;ensure&lt;/em&gt; type safety. The second point is that if you do not need dynamic features, then you are probably using Groovy as a better Java.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the last option was to comment to tell about why you need static compilation. 4 people chose that option, but didn’t comment, so unfortunately I won’t be able to tell much about that :-). But it’s already interesting to notice that this score is still higher (but not far) than people who don’t need static compilation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my talk, after this poll, I started explaining the semantic differences that may appear when you statically compile a program, as compared to dynamic behaviour. I did that because I expected my explanation to make some people change their mind about static compilation. Especially, the most visible difference comes from method dispatch (runtime based in dynamic Groovy or ahead of time in static Groovy). I wanted to tell people that this difference is probably the one which will ultimately make the decision about integrating static compilation in Groovy Core or not. I explained 3 options, which were Java-like method dispatch, dynamic groovy like method dispatch and inference based method dispatch. In the end, I asked people to tell which of the options they preferred:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://jroller.com/melix/resource/polls/method-dispatch.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To summarize once more the pros and cons of each method, I would say that:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java-like method dispatch has the advantage of well known semantics (though many people are uncapable of telling what precise corner cases would do in Java), but adds a lot of verbosity and disables &lt;em&gt;de facto&lt;/em&gt; some of the features we already implemented in the type checker (like flow typing).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamic Groovy like behaviour has the major advantage of keeping the same semantics as dynamic Groovy, but has also major problems. First, performance, because runtime time dispatch is much slower than compile time dispatch. Second, statically checking a dynamic program is always error prone: the compiler may think that method 1 would be called, though at runtime, method 2 would be (because Groovy chooses the best method at runtime according to the actual type arguments), so you would have a difference between what the compiler thinks and what is really done. This means that type safety cannot be ensured anymore…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inference based dispatch, which is the current implementation, which has the advantage of being close to dynamic groovy while preserving a high level of performance. The major problem with that solution being that we introduce a third semantics which is nor the one from Java, nor the one from dynamic Groovy. The question, in the end, is always: ``is it a problem?&apos;&apos;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Looking at the poll results, there are already two very interesting things to notice: first, very few people answered that question (14 persons, barely 4% of all viewers of the presentation). My interpretation is that the question is complex, and that not many people actually understand the problem (which also makes me think some talks about the subject are important ;-)). But this also confirms to me that even in Java, very few people are actually capable of interpreting how method dispatch works. Basically, I think the reasoning is much simpler. If a program doesn’t do what you expect, then you debug it and solve the problem, be it a dispatch problem or not. The second interesting figure, which I did not expect at all, is that nobody chose the Java option. Once more, I interpret this as people are not afraid of having different semantics as long as debugging is possible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ultimately, let’s compare the results of the two chosen options. Dynamic based dispatch has 6 answers, while inference based dispatch has 8. Being aware that most of the people who viewed the presentation weren’t at my talk and didn’t get the explanations about why I preferred inference based dispatch, I think the results are very interesting. If you consider that most people want static compilation for &lt;strong&gt;performance&lt;/strong&gt; and &lt;strong&gt;type safety&lt;/strong&gt; which, as I explained, cannot be ensured with dynamic based dispatch, the figures suddenly highlight a strong contradiction. Many people are interested in performance and type safety but still want to keep the dynamic behaviour. My traditional answer for that kind of people is that they should choose &lt;em&gt;invoke dynamic&lt;/em&gt; support which will appear in Groovy 2.0 too, as it will guarantee the runtime semantics of a dynamic groovy program while improving performance (though, be warned, type safety cannot be ensured). Of course, static compilation is primarily aimed at people who cannot use invoke dynamic. For that, it seems that the results are in the good direction, because as long as you are aware that you choose a different semantics, then you are not lost. Hopefully, as I said, static compilation is totally optional, so if you choose to use static compilation, you are warned that you will have a slightly different runtime semantics. People who make intensive use of unit tests will probably be very happy with that :-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last but not least, the polls are still open. Feel free to answer and comment, as feedback is really important. The most important thing, in the end, is the user community.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Update: below you’ll find the updated figures, as of February 9th, 2012:&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/polls/method-dispatch-20120209.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/polls/static-compilation-20120209.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Static type checking talk from Paris Groovy/Grails User Group</title>
      <link>https://melix.github.io/blog//2012/01/22/static_type_checking_talk_from.html</link>
      <pubDate>Sun, 22 Jan 2012 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2012/01/22/static_type_checking_talk_from.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_static_type_checking_and_compilation_in_groovy_2_0&quot;&gt;Static type checking and compilation in Groovy 2.0&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This week, I had an interesting 2 days work session at Paris (La Defense) with Guillaume Laforge, Jochen Theodorou and Rémi Forax as a guest star. On Thursday night, I talked about my work on &lt;em&gt;static type checking&lt;/em&gt; and experimental &lt;em&gt;static compilation&lt;/em&gt; at the &lt;a href=&quot;https://www.meetup.com/Paris-Groovy-Grails/events/45108892/&quot;&gt;Paris Groovy and Grails User Group&lt;/a&gt;. Here are the slides:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_some_comments&quot;&gt;Some comments&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, a large part of the session was spent in explaining what static type checking implies in terms of semantics for a language like Groovy. I tried to explain that &lt;em&gt;by definition&lt;/em&gt;, type checking a dynamic language is impossible, so you have to make decisions and drop support for dynamic features in that case. However, this is in most situations not a problem for people looking for static type checking, because what they need is to guarantee the behaviour of a program at runtime &lt;strong&gt;and&lt;/strong&gt; compile time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last part of the talk was spent in explaining the most important difference in behaviour between dynamic method dispatch and static method dispatch. This was necessary to introduce the experimental static compiler which should make its way in the next beta of Groovy 2.0. I tried to explain the three different options we have regarding static compilation and method dispatch:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java-like method dispatch, which has the main interest of being known of most people (at least, people who faced the problem once). This solution however has major drawbacks. In particular, it removes most of the interest of the flow typing mode, and requires extra verbosity which is the opposite of the Groovy philosophy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamic-Groovy like method dispatch. Typically, this is wanted to avoid a &lt;code&gt;third language&apos;&apos; (not Java, nor Groovy), and this is were you want a statically compiled Groovy program to behave at runtime like dynamic Groovy does. While this sounds interesting, it also has major problems. The first one is performance, which would be awful because we would have to introduce tons of &lt;/code&gt;instanceof&apos;&apos; checks at compile time to correctly dispatch methods. More complicated, this ``instanceof cascade&apos;&apos; would generate unreadable bytecode (think of parameter combinations) which would also be a major performance issue for CPUs (which, as Rémi said during the session, really do not like branching). Even worse, this wouldn’t work anymore if you subclass the statically compiled class because the new overloaded methods wouldn’t be known from the compiler. This is why I consider this solution the worse of all, though I understand people who want it. Last but not least, Groovy 2.0 will introduce &lt;strong&gt;InvokeDynamic&lt;/strong&gt; support which should greatly improve performance of dynamic Groovy without loosing its semantics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The third solution I presented is the one currently implemented in the experimental compiler: inference based method dispatch. This definitely creates a third language in terms of dispatch semantics, but as the developer explicitly adds an annotation, he should be aware of the differences (which only occur when you have overloaded methods). Inference based dispatch also has the advantage of being ``flow typing&apos;&apos; compatible, and removes a lot of verbosity. It has my preference, which explains why this is what is implemented right now.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Our guest star Rémi Forax also suggested an alternative solution, which would in theory maintain the semantics of dynamic Groovy, though we are in a statically compiled world. The idea is that when the compiler detects an overloaded method, it should generate the appropriate instanceof checks and seal the class (to avoid it to be subclassed). But as we discussed that solution the next day, we found some cases where even in that situation, we wouldn’t be able to guarantee dynamic Groovy like behaviour without adding explicit guards on every static method call (in particular, changing the metaclass or detection of category usage). This would also lead in a major performance penalty (Rémi couldn’t avoid telling us that all answers to our problem are in InvokeDynamic, but still, we want to offer something for pre-Java 7 people).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_future&quot;&gt;The future&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I ended the talk with a small view of what’s still to be done. There are still bugs in the static type checker (especially in loops where an overloaded method result is assigned to one of its parameters) and probably a lot more in the compiler. Eventually, I insisted on the fact that every point of both static type checking and static compilation &lt;strong&gt;are to be discussed with the community&lt;/strong&gt;. While static type checking will most probably be part of Groovy 2.0, it’s still unsure about static compilation, and that’s why we would like you to answer the surveys that are in the presentation.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_toward_a_new_mop&quot;&gt;Toward a new MOP&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As this session was a gift for static types lovers, we also wanted to offer something for our dynamic language users. This came with a long discussion about a new MOP (also known as MOP 2.0). The result of the discussion will be published by Guillaume Laforge as a new GEP (Groovy Enhancement Proposal). Once again, community will be involved.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Thanks a lot!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;French speaking users might also be interested in my talk at the &lt;a href=&quot;https://www.nantesjug.org/&quot;&gt;Nantes JUG&lt;/a&gt; which introduced &lt;a href=&quot;https://portal.sliderocket.com/vmware/Introduction-aux-DSLs-en-Groovy&quot;&gt;DSLs in Groovy&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>CodeNarc plugin for IntelliJ IDEA updated</title>
      <link>https://melix.github.io/blog//2012/01/18/codenarc_plugin_for_intellij_idea.html</link>
      <pubDate>Wed, 18 Jan 2012 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2012/01/18/codenarc_plugin_for_intellij_idea.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_codenarc_for_intellij_idea_0_16_1&quot;&gt;CodeNarc for IntelliJ IDEA 0.16.1&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Eventually, I managed to upgrade the CodeNarc for IntelliJ IDEA plugin to use CodeNarc 0.16.1. It took a while (sorry Hamlet ;)), but I faced an awful jar hell issue.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_java_lang_linkageerror&quot;&gt;java.lang.LinkageError&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s quite interesting indeed, though I am not fully happy with the ``fix&apos;&apos;. Let’s see what’s the problem. If any IntelliJ expert is here, I’d be happy to have some help. Basically, for compatibility with newer versions of Groovy, both CodeNarc and GMetrics (a dependency of CodeNarc) embed in their jar three classes which have disappeared from the newest Groovy version (in fact, they were moved in other packages):&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;org.codehaus.groovy.ast.expr.RegexExpression&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;org.codehaus.groovy.transform.powerassert.Value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;org.codehaus.groovy.transform.powerassert.ValueRecorder&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Normally, this shouldn’t be a problem, but when I ran the plugin, it failed loading with this cryptic error, well known from OSGI users:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;java.lang.LinkageError: loader constraint violation: loader (instance of com/intellij/ide/plugins/cl/PluginClassLoader) previously initiated loading for a different type with name &quot;org/codehaus/groovy/ast/expr/RegexExpression&quot;
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:465)
 at com.intellij.util.lang.UrlClassLoader._defineClass(UrlClassLoader.java:124)
 at com.intellij.util.lang.UrlClassLoader.defineClass(UrlClassLoader.java:120)
 at com.intellij.util.lang.UrlClassLoader._findClass(UrlClassLoader.java:96)
 at com.intellij.ide.plugins.cl.PluginClassLoader.d(PluginClassLoader.java:102)
 at com.intellij.ide.plugins.cl.PluginClassLoader.loadClass(PluginClassLoader.java:63)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Oh my, a LinkageError. Worse than a classical classpath issue. The problem comes from the fact that IntelliJ internally uses Groovy (where ?) and bundles &lt;em&gt;groovy-all-1.7.3.jar&lt;/em&gt;. I had to remove the compatibility classes from the CodeNarc jars in order to have the plugin loaded correctly. I think a better solution would be to be able to use an embedded version of Groovy, but the plugin loaded would always include those classes. By the way, it looks to me that CodeNarc would use the internal Groovy version to run (1.7.3) whereas it would probably be better if we could use the version used by the project…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Anyway, the plugin is upgraded, have fun!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy static type checker: status update</title>
      <link>https://melix.github.io/blog//2011/11/03/groovy_static_type_checker_status.html</link>
      <pubDate>Thu, 3 Nov 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/11/03/groovy_static_type_checker_status.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_about_groovy&quot;&gt;About Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As some of you may already know, I joined SpringSource/VMware a month ago and I am working on the Groovy language.One of my tasks, which will make me busy a little while, consists of developing a &lt;em&gt;static type checker&lt;/em&gt;. This project, internally, is known as &lt;em&gt;Grumpy&lt;/em&gt;. Why this name? Is it supposed to be public? Indeed; no. It’s an internal name only, because the main goal of this project is to make the compiler grumpy, meaning it will complain where regular Groovy does not. In this post, I will explain what &lt;em&gt;static type checking&lt;/em&gt; (STC) consists of, what is already implemented, what’s in progress and eventually, I will need your help. The Groovy language is community driven. While developers like me may propose features, we want to make sure that they are useful to the community and that they are implemented the way YOU expect it to be. This is why, at some points, we will ask you for a decision to be made. Most of times, decisions to be made are not related to technical issues, but rather behaviour issues. I will try to hint you where decisions are to be made, or when they have already been taken. Be sure to give your opinion, either commenting on this post, either sending an e-mail to the user mailing-list.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovy_static_type_checking&quot;&gt;Groovy Static Type Checking&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Update: Now &lt;a href=&quot;https://docs.codehaus.org/pages/viewpage.action?pageId=227053189&quot;&gt;Groovy 2.0.0-beta-1 has been released&lt;/a&gt; with the static type checker integrated! You can give it a try, and give us feedback of course.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First of all, you’ll want to take a look at the &lt;a href=&quot;https://docs.codehaus.org/display/GroovyJSR/GEP+8+-+Static+type+checking&quot;&gt;Groovy Enhancement Proposal&lt;/a&gt; page which describes what are the goals of this feature. Right now, it’s still in heavy development, so it’s being developed on its own branch (called &lt;em&gt;grumpy&lt;/em&gt;). Basically, the idea is to make Groovy complain at compile time about types, instead of runtime. In fact, as Jochen Theodorou &lt;a href=&quot;https://blackdragsview.blogspot.com/2011/10/flow-sensitive-typing.html&quot;&gt;explains on his blog post&lt;/a&gt;, the Groovy compiler in ``regular&apos;&apos; mode, cannot make many checks at compile time regarding types, missing properties, missing methods and so on, because the language allows runtime meta-programming. Runtime meta-programming allows you, for example, to dynamically add members to a class, change the methods which are invoked, change the return types, bind external properties, … This means that if a program was to be statically checked, then it would fail, although it would work perfectly at runtime. An example is better than words, let’s take this code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;String.metaClass.foo = { -&amp;gt; 1 }
assert &apos;Hello, World!&apos;.foo() == 1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you run it, then you will see that it’s perfectly fine: at &lt;strong&gt;runtime&lt;/strong&gt;, we modify the metaClass of the String class so that it adds a new method on the String class which is known as foo() and returns an int. If this program was to be statically checked, then it would fail at compile time, because the compiler would not find the ``foo&apos;&apos; method on the String class.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, why should we add STC if it will make the compiler fail where a program is perfectly valid ? In fact, there are many reasons for that. One of them is that Java programmers who discover Groovy are often amazed about the conciseness of the language as compared to Java, and start programming in Groovy like they would in Java, that is to say with types and leveraging the syntax of Groovy. The key here is that many programmers never use the dynamic features of Groovy, but rather use the language as a ``better Java syntax&apos;&apos;. If you don’t do runtime metaprogramming, then you can do static type checking. This drives me to another reason for using STC: fail early. It’s always better to discover errors at compile time that at runtime. No need for long talks here: you can easily imagine a program running perfectly fine for long, until it reaches a poorly tested branch where you made a typo:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;void method(String message) {
   if (rareCondition) {
 println &quot;Did you spot the error in this ${message.toUppercase()}?&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I tend to think that even if you use the dynamic features of Groovy (say, for example, builders), it’s good to be able type check parts of code you know should be statically checked.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_behaviour_of_the_static_type_checker&quot;&gt;The behaviour of the static type checker&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_implementation_details&quot;&gt;Implementation details&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now it’s time to give you more information about the static type checker, that is to say the current implementation. Basically, you activate the static type checker either by annotating a class or a method with &lt;em&gt;@TypeChecked&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.transform.TypeChecked

@TypeChecked
void method(String message) {
   if (rareCondition) {
 println &quot;Did you spot the error in this ${message.toUppercase()}?&quot;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I like code, so let’s see what the compiler has to say about this example, and let’s run it :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;2 compilation errors:

[Static type checking] - The variable [rareCondition] is undeclared.
 at line: 5, column: 8

[Static type checking] - Cannot find matching method java.lang.String#toUppercase()
 at line: 6, column: 46&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, it complains about an unbound variable, &lt;em&gt;rareCondition&lt;/em&gt;. The compiler cannot statically determine its type, which is not allowed. The second error demonstrates the fact that missing methods are now disallowed and replaced with a nice error message that helps you spot the typo. Those explain the primary goals of the static type checker:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;check for missing methods or properties and report error&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;check for type safety&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;type inferrence&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;support for ``GDK methods&apos;&apos;, that is to say methods added by Groovy to common classes, aka extension methods&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;support for Groovy idiomatic constructs like &lt;em&gt;with&lt;/em&gt;, &lt;em&gt;each&lt;/em&gt;, …&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are also secondary objectives, which are under discussion:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;flow typing (see &lt;a href=&quot;https://blackdragsview.blogspot.com/2011/10/flow-sensitive-typing.html&quot;&gt;Jochen’s post&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unification types&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;static compilation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_whats_implemented_whats_not_implemented&quot;&gt;What’s implemented, what’s not implemented&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The best way to find out what’s implemented or not is to checkout the &lt;em&gt;grumpy&lt;/em&gt; branch from &lt;a href=&quot;https://xircles.codehaus.org/projects/groovy/repo/git/repo&quot;&gt;Codehaus Git repository&lt;/a&gt; (also available on &lt;a href=&quot;https://github.com/groovy/groovy-core/tree/grumpy&quot;&gt;GitHub&lt;/a&gt; and have a look at the unit tests located in &lt;em&gt;src/test/groovy/transform/stc&lt;/em&gt;. Another way is to read the &lt;a href=&quot;https://docs.codehaus.org/display/GroovyJSR/GEP+8+-+Static+type+checking&quot;&gt;GEP-8 page on the wiki&lt;/a&gt; which gives you examples plus textual explanations. However, this page is not always up-to-date. Let’s show some nice examples of already implemented stuff:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy-style constructors checks&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Checks that arguments provided when using the Groovy-style constructors are valid. Especially, this will throw errors:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Dimension d = [100] // wrong number of arguments
Dimension d = [&apos;100&apos;,&apos;200&apos;] // wrong argument types

class A {
 int x
 int y
 }
A a = [x:100, y:200, z: 300] // missing property&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Type inferrence&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def myname = &apos;Cedric&apos;
&quot;My upper case name is ${myname.toUpperCase()}&quot;
println &quot;My upper case name is ${myname}&quot;.toUpperCase()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Type inference with spread operator&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def keys = [x:1,y:2,z:3]*.key
def values = [x:&apos;1&apos;,y:&apos;2&apos;,z:&apos;3&apos;]*.value
keys*.toUpperCase()
values*.toUpperCase()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;instanceof&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If we detect that we are in an ``instanceof&apos;&apos; block, we can avoid explicit casting:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Object o
if (o instanceof String) o.toUpperCase()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Flow typing&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As we already said, this is still under discussion, but the prototype static type checker already implements some kind of flow typing. It’s still buggy (I will let you discover how to mislead it ;-)), but already allows some nice things like this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class A {
 void foo() {}
}
def name = new A()
name.foo() // no need to cast
name = 1
name = &apos;123&apos;
name.toInteger() // no need to cast, and toInteger() is defined by DGM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To give you an idea, if we choose not to do flow typing (give your opinion about that!), then you would have to write this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class A {
 void foo() {}
}
def name = new A()
((Foo)name).foo() // no need to cast
name = 1
name = &apos;123&apos;
((String)name).toInteger() // no need to cast, and toInteger() is defined by DGM&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Casts are necessary because the &lt;em&gt;name&lt;/em&gt; variable is assigned multiple times with different incompatible types. Personnaly, I think flow typing is more Groovy style than ``regular&apos;&apos; typing.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_not_implemented&quot;&gt;Not implemented&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Currently, there are two major features that are not implemented:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Support for generics&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for Groovy idiomatic constructs like ``each&apos;&apos;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first one (generics) is already under heavy development (and is, I must admit, giving me headaches), and there’s not much to say about it (apart that it is really complicated to implement!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second point is trickier. We already support the &lt;em&gt;with&lt;/em&gt; idiomatic construct. However, we must pay attention on the constructs with uses closures as arguments, and that is the case with lots of Groovy extension methods like &lt;em&gt;each&lt;/em&gt;, &lt;em&gt;collect&lt;/em&gt;, … I think it is important that the static type checker deals with those before the first official beta including the STC goes out, but it requires decisions from the community.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_we_need_you&quot;&gt;We need you!&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Don’t worry, I won’t ask you to implement those features (though, if you want to, I will never prevent you from doing this :-D), but I do ask for your opinion. Before all, I will illustrate the problem with a simple example:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;[&apos;I&apos;,&apos;feel&apos;,&apos;grumpy&apos;].each {
   println it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is currently unsupported, and will throw an error, saying that you cannot call the &lt;em&gt;toUpperCase&lt;/em&gt; method on a &lt;em&gt;String&lt;/em&gt;. We all agree that it should not complain, and I am in favor of fixing this as soon as possible. However, we must decide &lt;em&gt;how&lt;/em&gt; to fix this, in a manner that allows, for example, library writers to be compatible with the type checker.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What’s the problem here ? Basically, the signature of the each method is the following:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;private static  Iterator each(Iterator iter, Closure closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It is defined in DefaultGroovyMethods, so it’s an extension method, and you could think of it as a method available on the &lt;em&gt;Iterator&lt;/em&gt; interface, thus, let’s modify the signature to make it clearer:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public static  Iterator each(Closure closure)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, the only thing we know at this point is that the &lt;em&gt;each&lt;/em&gt; method takes a closure as an argument, but:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;we don’t know what the implementor does with the closure&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;we don’t know what arguments will be used when calling the closure&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java doesn’t provide enough type information for us to infer the type of the arguments&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This means that the block of code representing the closure, in our example, cannot be type checked correctly, because we cannot infer the type of the arguments (here, the implicit &lt;em&gt;it&lt;/em&gt;) that will be used when the closure gets called.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For those who know Groovy++, it states that the problem has been solved by adding generics information to the DGM signatures. However, I don’t think this solution is perfect, and I’d rather like to propose various solutions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first, obvious solution is to let the developer explicitely specify types. This is a solution, but not really a Groovy one:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;[&apos;I&apos;,&apos;feel&apos;,&apos;grumpy&apos;].each { String it -&amp;gt;
   println it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The main idea is for the implementor to provide type information through an annotation. Let’s call this annotation &lt;em&gt;@ClosureTypeInfo&lt;/em&gt; (if you have better names…). Then I could write this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;void myMethod(@ClosureTypeInfo(argTypes=[String,Set]) Closure strategy) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This allows the type checker:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;to determine that the closure code block requires two arguments of types &lt;em&gt;String&lt;/em&gt; and &lt;em&gt;Set&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;to type check the closure code block using this type information&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem is that if your class is parameterized, then you can’t use generic types as the arguments of the closure:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class MyClass {
   void myMethod(@ClosureTypeInfo(argTypes=[T]) Closure strategy) { ... } // this is not allowed because of type erasure
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, another idea (which is probably the one used by Groovy++, but I could not determine if it is actually how it works) is to use the parameterized types from the declaring class. For example, we would change the &lt;em&gt;each&lt;/em&gt; signature to:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public static&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When used like this, the type checker will infer that the arguments used for the closure will be the parameterized types of the declaring class. Therefore, if you use &lt;em&gt;each&lt;/em&gt; on a List, then it is an each on an Iterator which is parameterized with , so we determine that the arguments which will be used by the each method will be a single String argument.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are aware of how Java generics work, you may wonder why we use the generic types from the declaring class, and not those from the method. Indeed, we could have the following method signature:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public static  Iterator each(@ClosureTypeInfo(useGenerics=true) Closure closure) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then, the type information from which the argument types would be taken would be those from the method call:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;[&apos;I&apos;,&apos;feel&apos;,&apos;grumpy&apos;].each {
   println it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now you have the explanation about why I don’t like this idea:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;awkward, not groovy at all, syntax&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;requires you to add type information although we want it to be inferred&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;why, in that case, not explicitely specify type information in the closure ?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Indeed, this is more understandable:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;[&apos;I&apos;,&apos;feel&apos;,&apos;grumpy&apos;].each { String it -&amp;gt;
   println it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, we must stick with the parameterized types from the class. Now, we must also take care of subclasses and extract parameterized types from superclasses. This is why I started dealing with generics before dealing with closure argument types. For example, this should work:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class StringList extends LinkedList {}
def list = new StringList()
...
list.each {
   println it.toUpperCase()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So we have an annotation that allows us to either provide explicit type information (classes used as arguments) or infer types from parameterized types. Note that in the latter case, this works great for methods like &lt;em&gt;each&lt;/em&gt;, &lt;em&gt;collect&lt;/em&gt;, … but this may not make any sense. For example, imagine that we didn’t use an annotation, and always inferred type from generics. Then imagine the following code:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class Foo {
    T foo(Closure cl) {
        cl.call(1)
    }
    U bar(Closure cl) {
        cl.call([] as Set)
    }
}

def foo = new Foo()
assert foo.foo {
    2*it
} == 2
assert foo.bar {
    it
}.class == HashSet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, the foo() and bar() methods both take a different closure arguments, but the annotation would have expected that both take two arguments (a String and a Set). So, in that case, we would definitely want the generics to be inferred from the method generics. If we do so, we’re back to the situation we described previously, where types are more likely to be written explicitely in the closure block rather than in a generic declaration. I am not sure how we should solve this, so any idea is welcome.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Additionaly, this annotation can also be used to solve another problem: how will the type checker know what kind of delegate is used? The delegation strategy changes the order to which the missing methods or properties are looked up in a closure. Depending on the context, the developer may want to say that the closure passed as an argument of a method must have a specified delegation strategy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Last thing in this long post, is things we won’t be able to solve (at least, I can’t think of any proper way to do this). For example, regular Groovy allows you to do this:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def strategy = { println it.toUpperCase() }
list.each(strategy)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In static mode, you’ll have, at least, to do this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def strategy = { String it -&amp;gt; println it.toUpperCase() }
list.each(strategy)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; you’ll have to keep in mind that the compiler cannot, in that case, check that the closure passed as an argument to the each method uses the correct argument types.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_last_word&quot;&gt;Last word&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I hope this post has given you the opportunity to better understand the goals of the static type checker in upcoming Groovy. It is also there for you to give your opinion, as we want the behaviour of the type checker to be ``community driven&apos;&apos;, that is to say we want to find a behaviour that matches your expectations. Eventually, feel free to contribute, and suggest ways to solve problems like the ones I have highlighted here. Thanks for reading!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JLangDetect 0.3 released with bundled language profiles</title>
      <link>https://melix.github.io/blog//2011/06/27/jlangdetect_0_3_released_with.html</link>
      <pubDate>Mon, 27 Jun 2011 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2011/06/27/jlangdetect_0_3_released_with.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s been a while since I did not release a new version of &lt;a href=&quot;https://code.google.com/p/jlangdetect&quot;&gt;JLangDetect&lt;/a&gt;, a simple Java library for language identification. I have made several changes to this version, which should make it simpler to integrate and test.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;package name changed from &lt;em&gt;com.lingway.jlangdetect&lt;/em&gt; to &lt;em&gt;me.champeau.jlangdetect&lt;/em&gt; : there have been several questions regarding licensing, and whether JLangDetect was related to Lingway or not. The answer is no : it’s a pet project I’m leading, so to be clearer about that, I decided to rename the main package.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;3 modules : &lt;em&gt;jlangdetect&lt;/em&gt;, &lt;em&gt;jlangdetect-europarl&lt;/em&gt; and &lt;em&gt;jlangdetect-extra&lt;/em&gt; :&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;jlangdetect&lt;/em&gt; provides the basic language identification tooling : learning algorithms and language detection support, but it does &lt;strong&gt;not&lt;/strong&gt; integrate any language profile. This is basically the same level of support as the previous releases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;jlangdetect-europarl&lt;/em&gt; provides an &lt;a href=&quot;https://www.statmt.org/europarl/&quot;&gt;Europarl&lt;/a&gt; based language detector which already includes resources for detecting languages for 21 european languages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;jlangdetect-extra&lt;/em&gt; extends the Europarl detector with 4 languages : Russian, Chinese, Japanese and Korean. Those detectors are less robust than the Europarl ones due to the lack of royalty-free resources available, but should be sufficient for most needs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;less memory usage: JLangDetect 0.3 introduces a simple algorithm to reduce the size of each language profile without loosing too much accuracy. In version 0.2, an Europarl based language detector for 11 languages took about 25MB of RAM. Now, you can detect 21 languages with only 4MB of RAM for language profiles.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_to_use_it&quot;&gt;How to use it ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The simplest way to use JLangDetect is to use the &lt;em&gt;UberLanguageDetector&lt;/em&gt; singleton, available in the &lt;em&gt;jlangdetect-extra&lt;/em&gt; module :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import  me.champeau.ld.UberLanguageDetector;
UberLanguageDetector detector = UberLanguageDetector.getInstance();

// ..

String language = detector.detectLang(&quot;ceci est un petit texte en français&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Alternatively, if you don’t need to detect russian, chinese, japanese or korean languages, you can use the &lt;em&gt;EuroparlDetector&lt;/em&gt; available in the &lt;em&gt;jlangdetect-europarl&lt;/em&gt; module. Note that you can still create your own language detector and register custom languages using the core module.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_maven_integration&quot;&gt;Maven integration&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect is now available through Maven. To use it, you can add the following repository into your pom.xml file :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;  jlangdetect-googlecode
  JLangDetect Maven repository
  https://jlangdetect.googlecode.com/svn/repo&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then use the following dependency :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;  me.champeau.jlangdetect
  jlangdetect-extra
  0.3&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_use_from_groovy&quot;&gt;Use from Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As a last integration example, here is how to use it from Groovy, through a simple script :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@GrabResolver(&apos;https://jlangdetect.googlecode.com/svn/repo&apos;)
@Grab(&apos;me.champeau.jlangdetect:jlangdetect-extra:0.3&apos;)
import me.champeau.ld.UberLanguageDetector as ULD

ULD.instance.with {
  assert detectLang(&apos;ceci est un petit texte en français&apos;) == &apos;fr&apos;
  assert detectLang(&apos;this is a text in english&apos;) == &apos;en&apos;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_direct_downloads&quot;&gt;Direct downloads&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://jlangdetect.googlecode.com/svn/repo/me/champeau/jlangdetect/jlangdetect/0.3/jlangdetect-0.3.jar&quot;&gt;JLangDetect 0.3 (jar)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://jlangdetect.googlecode.com/svn/repo/me/champeau/jlangdetect/jlangdetect-europarl/0.3/jlangdetect-europarl-0.3.jar&quot;&gt;JLangDetect Europarl 0.3 (jar)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://jlangdetect.googlecode.com/svn/repo/me/champeau/jlangdetect/jlangdetect-extra/0.3/jlangdetect-extra-0.3.jar&quot;&gt;JLangDetect Extra 0.3 (jar)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Customizing Groovy compilation process</title>
      <link>https://melix.github.io/blog//2011/05/12/customizing_groovy_compilation_process.html</link>
      <pubDate>Thu, 12 May 2011 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2011/05/12/customizing_groovy_compilation_process.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovy_compilation_customizers&quot;&gt;Groovy compilation customizers&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy 1.8 introduced the notion of compilation customizers. They are used to tweak the compilation process, in order, for example, to add imports to scripts transparently, apply AST transformations without annotating classes or limiting the language for security. In this post, I will show you how to use them, and how you can write your own customizer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prior to Groovy 1.8, you would have to override the &lt;em&gt;GroovyClassLoader&lt;/em&gt; and write several utility classes to add compilation units to the compilation process. While this worked, this was not really easy to do. Our first example will show you how easy it is now :&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_adding_imports_transparently&quot;&gt;Adding imports transparently&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the recurring questions on the Groovy mailing lists was how one could add default imports to scripts. Groovy, for example, imports the java.util classes by default, which improves readability, but there was no simple way to add your own. Now, you can use the &lt;em&gt;ImportCustomizer&lt;/em&gt; class :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import org.codehaus.groovy.control.customizers.ImportCustomizer

...

def importCustomizer = new ImportCustomizer()
// regular imports
importCustomizer.addImports(&apos;java.util.concurrent.atomic.AtomicInteger&apos;, &apos;java.util.concurrent.atomic.AtomicBoolean&apos;)
// star imports
importCustomizer.addStarImports(&apos;java.util.concurrent&apos;)
// static star imports
importCustomizer.addStaticStar(&apos;java.lang.Math&apos;)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then all you need to do is to create a compiler configuration where you will register the customizer :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(importCustomizer)
def shell = new GroovyShell(configuration)
shell.evaluate &quot;&quot;&quot;
  new AtomicInteger(0) // won&apos;t throw ClassNotFoundException
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The import customizer provides additional methods to specify, for example, import aliases. Take a look at the javadoc for more details. Now we will take a look at another customizer which is provided by default in Groovy 1.8 and allows you to secure the execution of your scripts.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_securing_user_scripts_thanks_to_the_secureastcustomizer&quot;&gt;Securing user scripts thanks to the SecureASTCustomizer&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The goal of this customizer is to filter the script to allow or disallow some constructs. For example, one building an arithmetic shell with Groovy would want to disallow the user to import or create classes, and limit the syntax to the basic operators. This can be achieved thanks to the &lt;em&gt;SecureASTCustomizer&lt;/em&gt;, which filters out AST nodes and throws a &lt;em&gt;SecurityException&lt;/em&gt; whenever a disallowed construct is used.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s take a look at the example from the Javadoc, which defines an arithmetic shell :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;final ImportCustomizer imports = new ImportCustomizer().addStaticStars(&apos;java.lang.Math&apos;) // add static import of java.lang.Math
final SecureASTCustomizer secure = new SecureASTCustomizer()
secure.with {
    closuresAllowed = false
    methodDefinitionAllowed = false

    importsWhitelist = []
    staticImportsWhitelist = []
    staticStarImportsWhitelist = [&apos;java.lang.Math&apos;] // only java.lang.Math is allowed

    tokensWhitelist = [
            PLUS,
            MINUS,
            MULTIPLY,
            DIVIDE,
            MOD,
            POWER,
            PLUS_PLUS,
            MINUS_MINUS,
            COMPARE_EQUAL,
            COMPARE_NOT_EQUAL,
            COMPARE_LESS_THAN,
            COMPARE_LESS_THAN_EQUAL,
            COMPARE_GREATER_THAN,
            COMPARE_GREATER_THAN_EQUAL,
    ].asImmutable()

    constantTypesClassesWhiteList = [
            Integer,
            Float,
            Long,
            Double,
            BigDecimal,
            Integer.TYPE,
            Long.TYPE,
            Float.TYPE,
            Double.TYPE
    ].asImmutable()

    receiversClassesWhiteList = [
            Math,
            Integer,
            Float,
            Double,
            Long,
            BigDecimal
    ].asImmutable()
}

// configuration ends here

CompilerConfiguration config = new CompilerConfiguration()
config.addCompilationCustomizers(imports, secure)
GroovyClassLoader loader = new GroovyClassLoader(this.class.classLoader, config)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, we allow static usage of java.lang.Math constants thanks to a static import added automatically through the &lt;em&gt;ImportCustomizer&lt;/em&gt; we’ve seen previously. Next comes the secure AST customizer configuration itself, which allows us to :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;disallow usage of closures and methods&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;disallow imports by setting an empty import whitelist&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;disallow static imports by setting an empty static import whitelist&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;only allow static import of java.lang.Math methods and constants&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;filter out the allowed tokens of the language by allowing mathematical symbols only (tokensWhitelist)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;filter out the types allowed to be used in the shell by explicitely specifying a list of allowed classes (note the usage of Float.TYPE, … for primitive types)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;eventually, limit the classes of objects for which method calls are allowed&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Doing this, a script like this one :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;1+1
---

will run perfectly, while this one :

code,prettyprint&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[source]&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;import org.codehaus.groovy.control.customizers.SecureASTCustomizer
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.control.CompilerConfiguration

class DeclarationExpressionChecker implements SecureASTCustomizer.ExpressionChecker {
    boolean isAuthorized(Expression expression) {
        if (expression instanceof DeclarationExpression) {
            if (expression.leftExpression instanceof VariableExpression) {
                def name = expression.leftExpression.name
                if (name[0]==name[0].toUpperCase()) { return false }
            }
        }

        true
    }
}

def secure = new SecureASTCustomizer()
secure.addExpressionCheckers(new DeclarationExpressionChecker())

def config = new CompilerConfiguration()
config.addCompilationCustomizers(secure)

def shell = new GroovyShell(config)
shell.evaluate &quot;&quot;&quot;
   def allowed = 1+1
   def Disallowed = 1+1
&quot;&quot;&quot;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this alternative example (suggested by &lt;a href=&quot;https://twitter.com/#!/hansamann/status/68676573552852992&quot;&gt;Sven Haiges&lt;/a&gt;), we will prevent the user from calling &lt;em&gt;System.exit()&lt;/em&gt; :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import org.codehaus.groovy.control.customizers.SecureASTCustomizer
import org.codehaus.groovy.ast.expr.*
import org.codehaus.groovy.control.CompilerConfiguration

class MethodCallExpressionChecker implements SecureASTCustomizer.ExpressionChecker {
    boolean isAuthorized(Expression expression) {
        if (expression instanceof MethodCallExpression) {
            if (expression.objectExpression instanceof ClassExpression) {
                if (expression.objectExpression.type.name==System.name) {
                    if (expression.methodAsString==&apos;exit&apos;) return false
                }
            }
        }

        true
    }
}

def secure = new SecureASTCustomizer()
secure.addExpressionCheckers(new MethodCallExpressionChecker())

def config = new CompilerConfiguration()
config.addCompilationCustomizers(secure)

def shell = new GroovyShell(config)
shell.evaluate &quot;&quot;&quot;
   System.exit(0)
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_applying_ast_transformations_transparently_with_the_asttransformationcustomizer&quot;&gt;Applying AST transformations transparently with the ASTTransformationCustomizer&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last customizer provided in Groovy 1.8 allows you to transparently add AST transformations to your scripts. This is particularly useful if you think about the new &lt;em&gt;ThreadInterrupt&lt;/em&gt; AST transformation, for example, which will not likely be added to scripts by hand. Another advantage of this customizer is to have an alternative to the global AST transformation mechanism, and can also be used to help the development of such global transforms. Usage is fairly easy :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(new ASTTransformationCustomizer(Log))
def shell = new GroovyShell(configuration)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, we define an ASTTransformationCustomizer which will automatically apply the @Log AST Transformations to all classes in the compilation unit. Note that it is interesting in two different ways :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it prevents the user from having to add the @Log transformation to each class he writes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it allows a local AST transformation (@Log) to be applied just as if it was a global one&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second point is important to understand, because it also shows a limit of this customizer : every class in the compilation unit will have the transformation applied, but there is no way to pass AST transformation arguments. For example, here, you cannot change the name of the generated field, while if you used the @Log annotation directly, you could have passed an argument for it. If you need to pass arguments, I encourage you to take a look at the source code of the &lt;em&gt;ASTTransformationCustomizer&lt;/em&gt; and write your own customizer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Transparently adding global AST transformations is not more complicated. Unlike local AST transformations, global AST transformations do not have a corresponding annotation, and do not have arguments, so you must refer to the ASTTransformation class itself :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def configuration = new CompilerConfiguration()
configuration.addCompilationCustomizers(new ASTTransformationCustomizer(MyASTTransformationClass))
def shell = new GroovyShell(configuration)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The difference from the local case is the type of the class passed as the argument of the customizer constructor. In the case of a local AST transformation, you must pass the annotation class, while in the global case, you pass the AST transformation class directly. Using this customizer, you have an alternative option to the &lt;em&gt;META-INF/services/org.codehaus.groovy.transform.ASTTransformation&lt;/em&gt; registration process.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_writing_your_own_customizer&quot;&gt;Writing your own customizer&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In addition to those 3 bundled customizers, you may want to write your own. To to this, you just have to extend the &lt;em&gt;org.codehaus.groovy.control.customizers.CompilationCustomizer&lt;/em&gt; abstract class, which is basically a &lt;em&gt;PrimaryClassNodeOperation&lt;/em&gt; for which the compiler phase is fixed. If you need to write a customizer, I strongly encourage you to read the &lt;em&gt;ImportCustomizer&lt;/em&gt; or &lt;em&gt;ASTTransformation&lt;/em&gt; customizer sources, which are quite simple to understand. Eventually, if you have particular needs or see potential improvements to the current implementations, do not hesitate to join the &lt;a href=&quot;https://groovy.329449.n5.nabble.com/&quot;&gt;mailing list&lt;/a&gt;, or raise &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY&quot;&gt;JIRA issue&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Inline assembly with Groovy&amp;#8230;&amp;#8203; Evil or awesome?</title>
      <link>https://melix.github.io/blog//2011/01/31/inline_assembly_with_groovy_evil.html</link>
      <pubDate>Mon, 31 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/31/inline_assembly_with_groovy_evil.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_inline_assembly_with_groovy_evil_or_awesome&quot;&gt;Inline assembly with Groovy… Evil or awesome ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m borrowing the title of this post from &lt;a href=&quot;https://twitter.com/#!/cbeust/status/26826212915544066&quot;&gt;a Tweet by Cédric Beust&lt;/a&gt;, the creator of &lt;a href=&quot;https://testng.org&quot;&gt;TestNG&lt;/a&gt; that followed my post about &lt;a href=&quot;https://www.jroller.com/melix/entry/asm_plugin_for_intellij_and&quot;&gt;inlining JVM bytecode instructions in Groovy&lt;/a&gt;. I have read many different reactions from this, going from stupid to awesome. Though I started this as an ironic response to the &lt;a href=&quot;https://www.jroller.com/melix/entry/yes_fibonacci_in_groovy_can&quot;&gt;languages micro-benchmarking frenzy&lt;/a&gt;, it seemed at the end that there was real interest for this. The question, now, is to determine whether this idea is, indeed, evil, or awesome.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of the first things to consider is that inlining JVM bytecode instructions is not inlining assembly. The code that we’re inlining is indeed &lt;em&gt;virtual machine instruction sequences&lt;/em&gt;. That it really important to understand, because a JVM won’t let you do nasty things. It’s really, when you’re inlining assembly code in a C program, to crash your program (or, worse, the operating system itself). In a JVM, every bytecode sequence gets &lt;em&gt;verified&lt;/em&gt; by the JVM before getting executed, and &lt;em&gt;checked&lt;/em&gt; at runtime just like regular code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What does it mean ? It means that you won’t be able to execute bytecode which does things regular Java code wouldn’t be authorized to do. Let’s take an example. One could think that you could, through bytecode instructions, bypass the fact that you have to use reflection to access private fields of a class from another one :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class Private {
    private int value;
}

@groovyx.ast.bytecode.Bytecode
void set(Private b, int x) {
    aload 1
    iload 2
    putfield Private.value &amp;gt;&amp;gt; int
    return
}

def bidon = new Private()
set(bidon, 5)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The previous code, when executed, throws the regular &lt;em&gt;java.lang.IllegalAccessError&lt;/em&gt;. It’s not different from what you would expect in pure Java. Now, what would happen if you wrote invalid bytecode sequences ? Do you think you would crash the JVM ? Let’s try :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@groovyx.ast.bytecode.Bytecode
int sum(int x, int y) {
    aload 1
    iload 2
    iadd
    ireturn
}

println sum(3,6)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can you spot the error ? It’s the first line of the bytecode sequence : &lt;em&gt;aload 1&lt;/em&gt; means push the reference of the first parameter object onto the stack. Here, the first parameter is not an object, but a primitive type (int), so we should have used &lt;em&gt;iload 1&lt;/em&gt;. Here’s the output of this program :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;Caught: java.lang.VerifyError: (class: Helper, method: sum signature: (II)I) Register 1 contains wrong type&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;No crash at all, your program is just invalid and buggy, but nothing harmful. From this point of view, the &lt;em&gt;@Bytecode&lt;/em&gt; annotation just provides another DSL for Groovy. It’s not different from any other DSL, apart from the fact that it’s translated directly into real JVM bytecode. Are DSLs inherently evil ? I don’t think so.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_so_wheres_the_evil&quot;&gt;So where’s the evil ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, I think the problem is that every feature you add to a language will eventually be used. So, what would prevent someone from writing his whole code with bytecode instructions ? How can this be maintainable ? Not everyone speaks bytecode (to be honest, I find this more readable than Clojure, but that’s another debate ;)).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s true, no one will prevent anyone from writing bytecode everywhere. But that’s exactly where code reviews and code analysis tools are useful : it’s easy to write crap with &lt;strong&gt;any language&lt;/strong&gt;. It’s easy not to follow conventions, and it’s easy to take wrong decisions : why would you want to write inline bytecode right into Groovy ? The first bad reason would be to improve performance. Most likely, it’s easier to write a Java class that you’ll use into your groovy code. The second bad reason would be because that’s cool. It is, but don’t try this at work. The third one would be to think you are smarter than the Java compiler. Here are, in my opinion, a few reasons why you would want to inline bytecode into Groovy code :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;you are a student having programming language theory and compilation courses&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you already use bytecode generation in a project, and using this annotation it’s incredibly easy to test bytecode sequences. It makes Groovy the perfect partner for developers who use dynamic bytecode generation (try the &lt;a href=&quot;https://www.jroller.com/melix/entry/asm_plugin_for_intellij_and&quot;&gt;IntelliJ IDEA plugin to have a real good combo&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you are a genius Groovy hacker and understand that inlining bytecode could help you save a bunch of metaclass resolutions, and smart enough to understand why writing a Java class wouldn’t help you much about that&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you have written a dynamic bytecode generator which uses Groovy instead of direct ASM code to produce the class file&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;you eventually want to write your own JVM language&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;playing around with bytecode instructions helps you becoming a better Java programmer (totally subjective)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, what do you think ? Evil ? Awesome ? Any good reason why you would allow or disallow inlined bytecode ?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy CodeNarc plugin for IntelliJ IDEA is out</title>
      <link>https://melix.github.io/blog//2011/01/23/groovy_codenarc_plugin_for_intellij.html</link>
      <pubDate>Sun, 23 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/23/groovy_codenarc_plugin_for_intellij.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve just released a &lt;strong&gt;&lt;a href=&quot;https://codenarc.sourceforge.net&quot;&gt;CodeNarc&lt;/a&gt;&lt;/strong&gt; plugin for IntelliJ IDEA. It adds the powerful static Groovy code analysis rules of CodeNarc right into IntelliJ. The inspections are available on the fly, and are configurable thanks to the regular IntelliJ inspections configuration window.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are a couple of screenshots :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jroller.com/melix/resource/codenarc/codenarc-idea.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/codenarc/codenarc-idea.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;
 &lt;a href=&quot;https://www.jroller.com/melix/resource/codenarc/codenarc-settings.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/codenarc/codenarc-settings.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The plugin is downloadable from the IntelliJ IDEA plugin repository or &lt;a href=&quot;https://github.com/melix/codenarc-idea&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>ASM plugin for IntelliJ and Groovy @Bytecode AST Transform updated</title>
      <link>https://melix.github.io/blog//2011/01/20/asm_plugin_for_intellij_and.html</link>
      <pubDate>Thu, 20 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/20/asm_plugin_for_intellij_and.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m releasing a new version of my ASM plugin for IntelliJ IDEA tonight, as well as a new version of the &lt;a href=&quot;https://www.jroller.com/melix/entry/groovy_bytecode_ast_transformation_released&quot;&gt;Groovy @Bytecode AST Transformation&lt;/a&gt;. Both are worth an upgrade as they greatly improve your experience :&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_asm_plugin_for_intellij_idea&quot;&gt;ASM plugin for IntelliJ IDEA&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The new version of the plugin provides several improvements :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Ability to show the differences between two versions of the bytecode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configuration of output verbosity : skip frames, skip code, skip debug and expand frames&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for showing bytecode of test classes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A new Groovy tab which displays Groovified code for the @Bytecode AST Transformation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Support for two types of Groovy code : legacy and Groovified&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The last two items are directly related to the upgrade of the Groovy AST bytecode transformation, and will make integration of ASM bytecode into Groovy even easier !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_improved_syntax_for_the_bytecode_ast_transformation&quot;&gt;Improved syntax for the @Bytecode AST Transformation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The new release of the transformation adds support for a Groovier syntax, mostly contributed by Guillaume Laforge. Basically, the AST Transformation now supports different syntaxes that you can mix :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a &lt;em&gt;legacy&lt;/em&gt; syntax which is as close as possible of the output of tools like &lt;em&gt;javap&lt;/em&gt; or the ASM plugin for Eclipse/IntelliJ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a &lt;em&gt;Groovified&lt;/em&gt; syntax which makes it really easy to embed bytecode into Groovy : just copy and paste !&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;if you use the &lt;a href=&quot;https://plugins.intellij.net/plugin/?idea&amp;amp;id=5918&quot;&gt;IntelliJ IDEA ASM plugin&lt;/a&gt;, you wont need to modify the generated bytecode to make it work with the @Bytecode transformation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, on the class you want to show the bytecode for, right click on the editor and choose ``Show bytecode outline&apos;&apos; : &lt;a href=&quot;https://www.jroller.com/melix/resource/asm/show-bytecode.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/show-bytecode.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The new plugin includes a third tab which shows generated Groovy code. Select the 3rd tab :&lt;br&gt;
 &lt;a href=&quot;https://www.jroller.com/melix/resource/asm/groovified-view.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/groovified-view.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You’ll notice that the syntax here is the legacy syntax, as close as possible to the javap output. Now, click on the settings tab and choose Groovified code style :&lt;br&gt;
 &lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/asm-settings.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;  &lt;a href=&quot;https://www.jroller.com/melix/resource/asm/asm-groovified-new.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/asm-groovified-new.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Right click on the editor to show bytecode again. The Groovified tab will now use the brand new syntax. You can click on the ``Show differences&apos;&apos; button to highlight the differences :&lt;br&gt;
 &lt;a href=&quot;https://www.jroller.com/melix/resource/asm/asm-bytecode-diff.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/asm-bytecode-diff.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I definitely wanted to keep the two syntaxes as both have great interest. Here are the differences :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Labels&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;l0&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;anyLabel:&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Groovified syntax uses regular Groovy labels, allowing you to use any label, not only the &lt;code&gt;l[0-9]+&lt;/code&gt; syntax&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Goto jumps&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;_goto l15&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;go to: myLabel&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The underscore is replaced with a Groovier go to: syntax&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;instanceof checks&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;_instanceof &apos;java/lang/String&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;instance of: String&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Just like the goto variation, but allows class literals to be specified directly, not only string literals&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fields access&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;putfield &apos;com/lingway/test/MaClasse.valeur&apos;,&apos;I&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;putfield MaClasse.valeur &amp;gt;&amp;gt; int&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;get/put (static) field instructions support direct class literals. Field type is specified by the right hand side of the expression, after the right shift operator&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Methods&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;invokevirtual &apos;java/lang/StringBuilder.append&apos;,&apos;(Ljava/lang/String;)Ljava/lang/StringBuilder;&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;invokevirtual StringBuilder.append(String) &amp;gt;&amp;gt; StringBuilder&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;method instructions support direct class literals. Field type is specified by the right hand side of the expression, after the right shift operator&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;`New&apos; operator&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;_new &apos;java/lang/String&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;newobject String&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;em&gt;newobject&lt;/em&gt; keyword, supporting the class directly, not as a string literal&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Arrays&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;newarray T_INT&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;newarray int&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports class literals as well as primitive types&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Multidimensional arrays&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;multianewarray &apos;[[Ljava/lang/Object;&apos;,2&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;multianewarray Object[][],2&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports classes directly, as well as primitive types&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Type casting&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;checkcast &apos;java/lang/String&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;checkcast String&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports class literals&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exceptions&lt;/p&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy syntax : &lt;code&gt;trycatchblock l0,l1,l2,&apos;java/lang/Throwable&apos;&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Groovified syntax : &lt;code&gt;trycatchblock l0,l1,l2,Throwable&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Supports class literals&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_downloads&quot;&gt;Downloads&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_plugin_for_idea&quot;&gt;Plugin for IDEA&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The plugin for IntelliJ IDEA can be downloaded directly from the plugin manager or from &lt;a href=&quot;https://github.com/downloads/melix/asm-bytecode-intellij/asm-bo-0.3.zip&quot;&gt;this link&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_groovy_bytecode_ast_transformation&quot;&gt;Groovy @Bytecode AST Transformation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Download the new release from &lt;a href=&quot;https://github.com/melix/groovy-bytecode-ast&quot;&gt;GitHub&lt;/a&gt; : &lt;a href=&quot;https://github.com/downloads/melix/groovy-bytecode-ast/groovy-bytecode-ast-0.3.jar&quot;&gt;groovy-bytecode-ast/groovy-bytecode-ast-0.3.jar&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy @Bytecode AST transformation released</title>
      <link>https://melix.github.io/blog//2011/01/16/groovy_bytecode_ast_transformation_released.html</link>
      <pubDate>Sun, 16 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/16/groovy_bytecode_ast_transformation_released.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Following &lt;a href=&quot;https://www.jroller.com/melix/entry/yes_fibonacci_in_groovy_can&quot;&gt;my post about Fibonacci performance in Groovy&lt;/a&gt;, Guillaume Laforge gently asked me to continue my work, so I’m releasing the first version of a Groovy AST transformation which allows you to write a method body directly as bytecode. There are several usages for this, but I think the most important is educational : it’s one of the simplest (if not the simplest) way of testing JVM bytecode.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s an example of what you may write :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@groovyx.ast.bytecode.Bytecode
int fib(int i) {
    iload 1
    iconst_2
    if_icmpge l1
    iload 1
    _goto l2
   l1
    aload 0
    iload 1
    iconst_2
    isub
    invokevirtual &apos;.fib&apos;, &apos;(I)I&apos;
    aload 0
    iload 1
    iconst_1
    isub
    invokevirtual &apos;.fib&apos; ,&apos;(I)I&apos;
    iadd
   l2
    ireturn
}
println fib(40)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The documentation about how to write bytecode and the supported features are on the &lt;a href=&quot;https://github.com/melix/groovy-bytecode-ast/wiki&quot;&gt;project homepage at GitHub&lt;/a&gt;. The source code is licensed under the Apache License version 2. If you find any bug or have feature requests, please fill in the &lt;a href=&quot;https://github.com/melix/groovy-bytecode-ast/issues&quot;&gt;bug tracker&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_downloads_and_sources&quot;&gt;Downloads and sources&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You must use the groovy-all version of Groovy for this AST transform to work. Then, download the following jar :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/downloads/melix/groovy-bytecode-ast/groovy-bytecode-ast-0.1.0.jar&quot;&gt;groovy-bytecode-ast-0.1.0.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Sources are built with &lt;a href=&quot;https://gradle.org/&quot;&gt;Gradle&lt;/a&gt; and tests made with &lt;a href=&quot;https://code.google.com/p/spock/&quot;&gt;the Spock framework&lt;/a&gt;. Unit tests are also a great source of documentation, do hot hesitate to check them out.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Yes, Fibonacci in Groovy can be as fast as Java !</title>
      <link>https://melix.github.io/blog//2011/01/11/yes_fibonacci_in_groovy_can.html</link>
      <pubDate>Tue, 11 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/11/yes_fibonacci_in_groovy_can.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;After reading this, take a look at the complete @Bytecode AST transformation implementation &lt;a href=&quot;https://www.jroller.com/melix/entry/asm_plugin_for_intellij_and&quot;&gt;here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Yes, the famous Fibonacci test can be as fast in Groovy that it is in Java. In fact, Vaclav Pech showed us that &lt;a href=&quot;https://www.jroller.com/vaclav/entry/memoize_groovy_functions_with_gpars&quot;&gt;it could even be faster&lt;/a&gt;. Here, I’ll show you how you can acheive the same level of performance as Java without changing the algorithm. I have buzzed on Twitter saying this was a pure Groovy solution. In fact, I’m cheating a little, as one would consider this is not really pure Groovy, but indeed, you can do this only with .groovy files.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_it_all_started_with_one_quote&quot;&gt;It all started with one quote&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Around one discussion about the integration of Groovy++ into Groovy, which always end up with benchmarks comparisons, Jochen Theodorou said :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, with the AST transforms you could also generate java bytecode directly. Many things are possible with Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;When Jochen speaks, everyone listens. I did so. Was he really saying that I could generate &lt;strong&gt;bytecode&lt;/strong&gt; through AST transformations ? I’ve read this phrase carefully multiple times, then digged into the Groovy source code, and indeed, there was a &lt;em&gt;BytecodeSequence&lt;/em&gt; AST Node. Wow. Groovy never stops surprising me. Ok, so let’s start a proof of concept, and let’s do it with the king of the benchmarks (my appreciation), the Fibonacci benchmark.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_java_vs_groovy&quot;&gt;Java vs Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This benchmark is really interesting, because it shows us where Groovy is really bad against Java. That’s not important to me as I reckon this is not what Groovy is made for, but well, you know, benchmarks are all around, and people get nasty when they start telling your-favorite-language-is-crap-because-it-s-too-slow. I’m going to show you what I can do with Groovy, guys ! So here’s a Java implementation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public int fib(int i) {
   return i &amp;lt; 2 ? 1 : fib(i - 2) + fib(i - 1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And now, it’s Groovy counterpart :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;int fib(int i) {
   i &amp;lt; 2 ? 1 : fib(i - 2) + fib(i - 1);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Definitely similar, but Groovy 1.7.6 runs this 30x slower than Java…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovys_revenge_part_1_asm&quot;&gt;Groovy’s revenge, part 1 : ASM&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first episode for Groovy’s revenge consists of writing an &lt;a href=&quot;https://www.jroller.com/melix/entry/asm_bytecode_outline_for_intellij&quot;&gt;ASM plugin for IntelliJ IDEA&lt;/a&gt;, because, you know, it was such a pain to work with Eclipse. That’s done.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovys_revenge_part_2_ast_transformations&quot;&gt;Groovy’s revenge, part 2 : AST Transformations&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second episode, and most interesting, consists of writing an AST Transformation that will allow you to write bytecode right into Groovy. I did that, and here’s what my final script looks like :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@ast.Bytecode
int fib(int i) {
 l0
    iload 1
    iconst_2
    if_icmpge l1
    iconst_1
    _goto l2
 l1
    frame SAME
    aload 0
    iload 1
    iconst_2
    isub
    invokevirtual &apos;.fib&apos;,&apos;(I)I&apos;
    aload 0
    iload 1
    iconst_1
    isub
    invokevirtual &apos;.fib&apos;, &apos;(I)I&apos;
    iadd
 l2
   frame same1,&apos;I&apos;
    ireturn
}

int groovyFib(int i) { i&amp;lt;2?1:groovyFib(i-2)+groovyFib(i-1)}
println &quot;Pure Groovy&quot;
long sd = System.currentTimeMillis()
println groovyFib(40)
println &quot;Computed in ${(System.currentTimeMillis()-sd)}ms&quot;

println &quot;Bytecode Groovy&quot;
sd = System.currentTimeMillis()
println fib(40)
println &quot;Computed in ${(System.currentTimeMillis()-sd)}ms&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And here’s the output :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Pure Groovy
165580141
Computed in 18465ms
Bytecode Groovy
165580141
Computed in 576ms&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Annotating a method with &lt;em&gt;@Bytecode&lt;/em&gt; allows you to write it’s body in JVM pseudo-bytecode (you’ll notice some slight differences), but it’s almost exactly the same as what the ASM plugin will show when you display the bytecode of a method.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Interested in the AST Transformation code ? Here it is. Note that it is in very early stages, and I wrote this as a proof-of-concept. I’m unsure that there’s really a need for such a powerful tool in Groovy, that’s mostly fun for me ! However, it could be useful for self-generating code, you know, all the stuff about robots that write their own code and eventually generate giant networks of machines which destroys humanity… Maybe that could be useful for dynamic recompilation too, like what’s done in many emulators. However, if you think that could be interesting to have a complete implementation, let me know and I could push the code so that it comes as a Groovy module.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code. It’s surprisingly easy. However, you’ll have to use the &lt;em&gt;groovy-all&lt;/em&gt; jar to get this work, because the bytecode AST transformations uses the embedded &lt;em&gt;ASM&lt;/em&gt; library which is relocated at build time. The first and easy step is the AST annotation itself :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package ast

import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
import org.codehaus.groovy.transform.GroovyASTTransformationClass

@Retention(RetentionPolicy.SOURCE)
@Target([ElementType.METHOD])
@GroovyASTTransformationClass([&quot;ast.BytecodeASTTransformation&quot;])
public @interface Bytecode {

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then the implementation of the transformation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package ast

import groovyjarjarasm.asm.Label
import groovyjarjarasm.asm.MethodVisitor
import groovyjarjarasm.asm.Opcodes
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.expr.ArgumentListExpression
import org.codehaus.groovy.ast.expr.MethodCallExpression
import org.codehaus.groovy.ast.expr.VariableExpression
import org.codehaus.groovy.ast.stmt.ExpressionStatement
import org.codehaus.groovy.classgen.BytecodeInstruction
import org.codehaus.groovy.classgen.BytecodeSequence
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation

@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class BytecodeASTTransformation implements ASTTransformation, Opcodes {
 void visit(ASTNode[] nodes, SourceUnit source) {
  def meth = nodes[1]
  def instructions = meth.code.statements
  meth.code = new BytecodeSequence(new BytecodeInstruction() {
   @Override
   void visit(MethodVisitor mv) {
    def labels = [:]
    // perform first visit to collect labels
    instructions.each { ExpressionStatement stmt -&amp;gt;
     def expression = stmt.expression
     if (expression instanceof VariableExpression) {
      def text = expression.text
      if (text ==~ /l[0-9]+/) {
       labels.put(text, new Label())
      }
     }
    }
    instructions.each { ExpressionStatement stmt -&amp;gt;
     def expression = stmt.expression
     if (expression instanceof VariableExpression) {
      def text = expression.text
      if (text ==~ /l[0-9]+/) {
       mv.visitLabel(labels[text])
      } else if (text =~ /[aild]const|[aild]sub|[aild]add|[aild]return/) {
       mv.visitInsn(Opcodes.&quot;${text.toUpperCase()}&quot;)
      } else {
       throw new IllegalArgumentException(&quot;Bytecode operation unsupported : &quot;+text);
      }
     } else if (expression instanceof MethodCallExpression) {
      if (expression.objectExpression instanceof VariableExpression &amp;amp;&amp;amp; expression.arguments instanceof ArgumentListExpression) {
       if (expression.objectExpression.text==&quot;this&quot;) {
        def opcode = expression.methodAsString.toUpperCase()
        ArgumentListExpression args = expression.arguments
        switch (opcode) {
         case &apos;_GOTO&apos;:
          mv.visitJumpInsn(GOTO, labels[args.expressions[0].text])
          break;
         case &apos;IF_ICMPGE&apos;:
         case &apos;IF_ICMPLE&apos;:
         case &apos;IF_ICMPNE&apos;:
         case &apos;IF_ICMPLT&apos;:
         case &apos;IF_ICMPGT&apos;:
          mv.visitJumpInsn(Opcodes.&quot;${opcode}&quot;, labels[args.expressions[0].text])
          break;
         case &apos;ALOAD&apos;:
         case &apos;ILOAD&apos;:
          mv.visitVarInsn(Opcodes.&quot;${opcode}&quot;, args.expressions[0].text as int)
          break;
         case &apos;INVOKEVIRTUAL&apos;:
          def (clazz,call) = args.expressions[0].text.split(/\./)
          def signature = args.expressions[1].text
          if (!clazz) clazz = meth.declaringClass.name
          mv.visitMethodInsn(INVOKEVIRTUAL, clazz, call, signature)
          break;
         case &apos;FRAME&apos;:
          def frameId = args.expressions[0].text.toUpperCase()
          if (&apos;SAME&apos;==frameId) {
           mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
           break;
          } else if (&apos;SAME1&apos;==frameId) {
           if (args.expressions[1].text==&apos;I&apos;) {
            mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, [Opcodes.INTEGER] as Object[]);
            break;
           }
          }
         default:
          throw new IllegalArgumentException(&quot;Bytecode operation unsupported : &quot;+expression);
        }
       } else {
        throw new IllegalArgumentException(&quot;Bytecode operation unsupported : &quot;+expression);
       }
      } else {
       throw new IllegalArgumentException(&quot;Bytecode operation unsupported : &quot;+expression);
      }
     } else {
      throw new IllegalArgumentException(&quot;Bytecode operation unsupported : &quot;+expression);
     }
    }
   }
  })
 }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The code shows that there are many bytecode instructions that I did not manage. This is because I just wanted a proof-of-concept, so I mostly dealt with the instructions required to make the Fibonacci test run. However, thanks to Groovy dynamic nature, the code is rather compact, and consists of three steps :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Visit the method AST node to replace bytecode pseudo-instructions with a BytecodeSequence AST Node&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;which requires visiting the code block itself to collect the labels&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;then generate the visit instructions&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;My conclusion is rather simple : Groovy is amazing. Even when you think it’s beaten by another JVM language, you’ll always find room for improvement. This one looks like the most absolute solution : the DIY way, which reminds me when I was young and that I wrote assembler code on an Amstrad CPC 6128 for demos. This was fun, and I’m having fun again ! For you, if you find this code useful, then it’s a world of verify errors that opens to you. Good luck !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Footnote : for those who don’t get the irony, this is obvioulsy not a solution for making Groovy faster. It’s a nonsense to take a benchmark like this and say ``Groovy is slow&apos;&apos;. I’ve blogged many times about Groovy performance and showed this is rarely an issue. No, this point is about AST transformations, and how you could use bytecode to extend the language and implement missing features at the lower level.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>ASM Bytecode Outline for IntelliJ IDEA</title>
      <link>https://melix.github.io/blog//2011/01/09/asm_bytecode_outline_for_intellij.html</link>
      <pubDate>Sun, 9 Jan 2011 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2011/01/09/asm_bytecode_outline_for_intellij.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_an_asm_bytecode_outline_plugin_for_intellij_idea&quot;&gt;An ASM bytecode outline plugin for IntelliJ IDEA&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today, I’ve just submitted a new plugin which integrates &lt;a href=&quot;https://asm.ow2.org/index.html&quot;&gt;ASM&lt;/a&gt; bytecode views into IntelliJ IDEA : it’s a bytecode outline plugin similar to &lt;a href=&quot;https://asm.ow2.org/eclipse/index.html&quot;&gt;the one provided for Eclipse&lt;/a&gt;. It was really a pain for me to work with Eclipse, so I eventually decided to write my own plugin for my favorite IDE. It’s in early stages, but it just suits my needs right now.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have released it under an Apache 2 license, so there’s no problem for you to contribute if you want to improve it. By the way, this is also a test for me, since source code is available at &lt;a href=&quot;https://github.com/melix/asm-bytecode-intellij&quot;&gt;GitHut&lt;/a&gt; and that I’m not really familiar with Git concepts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Until the release is available from Jetbrain’s plugin manager, you may download the first release &lt;a href=&quot;https://github.com/downloads/melix/asm-bytecode-intellij/asm-bo-0.2.zip&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_update&quot;&gt;Update&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve uploaded a new version (0.2) which solves a problem under Windows, and doesn’t force compile when not necessary.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here are a couple of screenshots :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://www.jroller.com/melix/resource/asm/outline.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/outline.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;
&lt;br&gt;
 &lt;a href=&quot;https://www.jroller.com/melix/resource/asm/asmified.png&quot;&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/asm/asmified.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/a&gt;&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_usage&quot;&gt;Usage&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s fairly easy : just right click on the editor, and choose ``Bytecode Outline&apos;&apos;. Your class will be compiled, and the bytecode will be shown in the tool window on the right. Note that I plan not to compile the class if the binary is up to date, but I’m facing a strange bug in IntelliJ right now when I do so.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Getting TestNG, Spock and Cobertura to work together with Maven</title>
      <link>https://melix.github.io/blog//2010/12/28/getting_testng_spock_and_cobertura.html</link>
      <pubDate>Tue, 28 Dec 2010 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2010/12/28/getting_testng_spock_and_cobertura.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cobertura, TestNG and Maven play well together. However, I had problems when I started migrating some tests to &lt;a href=&quot;https://code.google.com/p/spock/&quot;&gt;the Spock framework&lt;/a&gt;. Long story short, Spock uses JUnit internally, not TestNG, and the surefire plugin only triggers tests for one of those frameworks at a time. Therefore, if you mix TestNG with Spock, you’ll run with problems where your Spock tests won’t be started automatically by Maven, and eventually, Cobertura will never generate test coverage for the corresponding classes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have found different proposals for fixing this problem, but only one worked for me, so here’s my working pom.xml :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;...

                1.7.6
  0.5-groovy-1.7
  1.2

...



   org.testng
   testng
   5.8
   test
   jdk15


   org.codehaus.groovy
   groovy-all
   ${groovy.version}


     junit
     junit


     org.apache.ant
     ant


     org.apache.ant
     ant-launcher


     jline
     jline





   org.spockframework
   spock-core
   ${spock.version}
   test



   org.codehaus.gmaven.runtime
   gmaven-runtime-1.7
   ${gmaven.version}


     org.codehaus.groovy
     groovy-all



...





    org.codehaus.gmaven
    gmaven-plugin
    ${gmaven.version}



       1.7


       generateStubs
       compile
       generateTestStubs
       testCompile






    org.apache.maven.plugins
    maven-surefire-plugin
    2.7.1


      test

       test


       none:none



      test-testng
      test

       test


       none:none





    org.spockframework
    spock-maven
    ${spock.version}



       find-specs





    org.codehaus.mojo
    cobertura-maven-plugin
    2.4


      cobertura-test
      package

       cobertura



        false




      cobertura-clean
      clean

       clean&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The trick is to add two executions of the surefire plugin, as &lt;a href=&quot;https://bit.ly/ePc0oG&quot;&gt;indicated here&lt;/a&gt;, but forcing the plugin version to 2.7.1. Also, adding two dependencies to the surefire plugin, as suggested by &lt;a href=&quot;https://twitter.com/#!/krosenvold/status/19442054924861441&quot;&gt;Kristian Rosenvold&lt;/a&gt; didn’t work for me. My pom.xml file also includes the necessary configuration for GMaven to work with Groovy 1.7 instead of 1.6 by default.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy Xmas gift : converting a number to its french writing</title>
      <link>https://melix.github.io/blog//2010/12/23/groovy_xmas_gift_converting_a.html</link>
      <pubDate>Thu, 23 Dec 2010 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2010/12/23/groovy_xmas_gift_converting_a.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you ever studied French, you must have struggled with its writing of numbers. There are various exceptions which even for natives are not easy to deal with. Fortunately, here’s a Groovy script that will help you. Okay, I did this because I remembered about a similar exercise I had several years ago in Caml I solved using pattern matching. I was thinking about a solution in Groovy. Here’s the result :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;/**
 * Convertit un nombre en lettres.
 * Les règles d&apos;écriture sont celles décrites sur https://www.miakinen.net/vrac/nombres
 *
 * @author Cédric Champeau (https://twitter.com/CedricChampeau)
 *
 */
def digits = [&apos;zéro&apos;,&apos;un&apos;,&apos;deux&apos;,&apos;trois&apos;,&apos;quatre&apos;,&apos;cinq&apos;,&apos;six&apos;,&apos;sept&apos;,&apos;huit&apos;,&apos;neuf&apos;]
def specials = [&apos;dix&apos;,&apos;onze&apos;,&apos;douze&apos;,&apos;treize&apos;, &apos;quatorze&apos;, &apos;quinze&apos;,&apos;seize&apos;]
def tens=[20:&apos;vingt&apos;,30:&apos;trente&apos;,40:&apos;quarante&apos;,50:&apos;cinquante&apos;,60:&apos;soixante&apos;,80:&apos;quatre-vingt&apos;,81:&apos;quatre-vingt-un&apos;]
def asLetters
asLetters = { number -&amp;gt;
   number&amp;lt;0?&quot;moins ${asLetters(-number)}&quot;:
   number&amp;lt;10?digits[number]:
   number&amp;lt;17?specials[number-10]:
   number&amp;lt;20?&quot;dix-${asLetters(number-10)}&quot;:
   number==80?&apos;quatre-vingts&apos;:
   number&amp;lt;100?tens[number]?:(
       number&amp;gt;69 &amp;amp;&amp;amp; number&amp;lt;80?&quot;soixante${number==71?&apos; et &apos;:&apos;-&apos;}${asLetters(number-60)}&quot;:
       number&amp;gt;89?&quot;quatre-vingt-${asLetters(number-80)}&quot;:
       (number%10==1)?&quot;${asLetters(number-1)}${number&amp;lt;70?&apos; et un&apos;:asLetters(number-70)}&quot;:&quot;${(number-number%10)==80?&apos;quatre-vingt&apos;:asLetters(number-number%10)}-${asLetters(number%10)}&quot;):
   number==100?&apos;cent&apos;:
   number&amp;lt;1000?&quot;${((int)(number/100))&amp;gt;1?(asLetters((int)number/100)+&apos; &apos;):&apos;&apos;}cent${number%100==0?&apos;s&apos;:&apos; &apos;+asLetters(number%100)}&quot;:
   number==1000?&apos;mille&apos;:
   number&amp;lt;1000000 &amp;amp;&amp;amp; ((number/1000)&amp;gt;1 &amp;amp;&amp;amp; ((int)number/1000)%100==0)?&quot;${asLetters((int)number/100000)} cent mille${number%1000==0?&apos;&apos;:&apos; &apos;+asLetters(number%1000)}&quot;:
   number&amp;lt;1000000?&quot;${((int)(number/1000))&amp;gt;1?(asLetters((int)number/1000)+&apos; &apos;):&apos;&apos;}mille${number%1000==0?&apos;&apos;:&apos; &apos;+asLetters(number%1000)}&quot;:
   number&amp;lt;1000000000?&quot;${number/1000000 as int==80?(&apos;quatre-vingt&apos;+(number%1000000&amp;gt;0?&apos;&apos;:&apos;s&apos;)):asLetters((int)(number/1000000))} million${((int)(number/1000000))&amp;gt;1?&apos;s&apos;:&apos;&apos;}${number%1000000&amp;gt;0?&apos; &apos;+asLetters((int)number%1000000):&apos;&apos;}&quot;:
   &quot;${number/1000000000 as int==80?(&apos;quatre-vingt&apos;+(number%1000000000&amp;gt;0?&apos;&apos;:&apos;s&apos;)):asLetters((int)(number/1000000000))} milliard${((int)(number/1000000000))&amp;gt;1?&apos;s&apos;:&apos;&apos;}${number%1000000000&amp;gt;0?&apos; &apos;+asLetters((int)number%1000000000):&apos;&apos;}&quot;
}
(1..100).each { println &quot;$it : ${asLetters(it)}&quot; }
[200,210,300,1100,1200,1999,1342,
1001,1011,2000,2011,-2100,2101,2222,2999,12000,12101,54122,
80000,122000,999999,154322,1154322,13154399,177412666451
,100000000,10000000001,200001,80000000,80000001,80000000000,80000000001,300000,
82015, 200000,200000000].each { println &quot;$it : ${asLetters(it)}&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Edit: Fixed &lt;code&gt;80&apos;&apos; written &lt;/code&gt;quatre-vingt&apos;&apos;. Sorry about the inline indenter, but copy/paste it and you’ll have a better rendering or &lt;a href=&quot;https://groovyconsole.appspot.com/script/362001&quot;&gt;check this&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The next step would be to make it even more groovy. But it showed me Groovy misses some interesting features of Caml : pattern matching is interesting as it deals with multiple left hand side patterns, where closures only allow one signature with a single parameter. Here, I used indenting and over-used the ternary operator to emulate this behaviour.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine you could write something like this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def asLetters = { (..&amp;lt;0) -&amp;gt; &quot;moins ${asLetters(-it}&quot;
 | (0..10) -&amp;gt; digits[it]
 | it&amp;lt;17 -&amp;gt; specials[number-10]
 | ...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What do you think ? Would it be more readable ?&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Upcoming Groovy goodness : automatic thread interruption</title>
      <link>https://melix.github.io/blog//2010/11/30/upcoming_groovy_goodness_automatic_thread.html</link>
      <pubDate>Tue, 30 Nov 2010 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2010/11/30/upcoming_groovy_goodness_automatic_thread.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using Groovy can really be addictive. It deals with so many different problems that you’ll eventually end up using it everywhere in your application. One of the situations that I think is widely used is embedding Groovy for your business logic. For example, embedding a Groovy DSL which allows users to customize their application or even run scripts on your platform. However, when doing this, you expose your infrastructure dangerously : what if a user accidently creates an infinite loop ? What if another creates a memory leak ? Would it be reasonable if your whole application goes down because a customer just ran &lt;em&gt;one poor script&lt;/em&gt; ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are common solutions for that, but most are not suitable. The real solution would be to isolate the script from the rest of the application by spawning it in its own process. However, this may be complicated to do if you need to share objects from the original VM.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;As I had this problem multiple times in the past, I proposed a patch to Groovy 1.8 introducing a new AST Transformation which was just, at the beginning, an elegant solution for interrupting loops and closures when the running thread has been interrupted. Eventually, thanks to the Groovy folks (and a special mention to Hamlet D’Arcy), we ended up with three separate annotations that I’ll describe here.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_basic_example&quot;&gt;A basic example&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s the most basic example : how would you manage this ?&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;while (true) {
 // eat cpu
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You can test it in the Groovy console (&lt;em&gt;groovyConsole&lt;/em&gt; command), and try to click on the script interruption button. Most likely you won’t be able to click on the script interruption button because the script doesn’t even make a call to &lt;em&gt;Thread.yield()&lt;/em&gt; which does not let a chance to the UI thread to catch up. If you could, Groovy would have sent an interruption request to the script thread. However, even in that case, the script thread would never stop because no one ever checks for interruption. Here’s where the first annotation comes up.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_new_ast_transformations&quot;&gt;New AST Transformations&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note that the following is based on an early implementation and subject to changes. Those annotations are available since the Groovy 1.8.0-beta-3 release.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_threadinterrupt&quot;&gt;@ThreadInterrupt&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is the most basic transformation we can apply. The script above becomes :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@ThreadInterrupt
import groovy.transform.ThreadInterrupt

while (true) {
// eat cpu
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you run it in the Groovy 1.8.0-beta3 console, you will not notice any change, apart from the fact that you can click on the interrupt button now. If you do so, you’ll see an exception thrown :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;java.lang.InterruptedException: Execution Interrupted
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The magic here is that our transformation automatically added a thread interruption check in the loop block. Thus, the annotated code is equivalent to the following :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;while (true) {
  if (Thread.currentThread().isInterrupted()) throw new InterruptedException(&quot;Execution Interrupted&quot;);
// eat cpu
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s all ! Adding this annotation ensures that &lt;em&gt;for&lt;/em&gt;, &lt;em&gt;while&lt;/em&gt;,&lt;em&gt;do&lt;/em&gt; loops and closures will have an interruption check added. It will also add a check on method start. This annotation also applies on classes. The behaviour of the transformation can also be tuned for your needs :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;checkOnMethodStart&lt;/em&gt; annotation parameter (defaults to true) adds an interrupt check as the first statement of a method body&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;applyToAllClasses&lt;/em&gt; annotation parameter (default to true) will apply the transformation to every class in your script (or compilation unit if not in a script), therefore allowing to interrupt more complex method call pathes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You may wonder what use is this transform if the user has to explicitely add it to scripts (s)he writes. However, the good thing is that you can do it automatically, because Groovy scripts accept import statements anywhere. So basically, you could take the user code, append the annotated import, and you’d see the expected behaviour.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_timedinterrupt&quot;&gt;@TimedInterrupt&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The second AST Transformation to be added allows interrupting a script after a maximum execution time. It is interesting when you want to automatically timeout scripts. For example :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@TimedInterrupt(10)
import groovy.transform.TimedInterrupt

while (true) {
// eat cpu
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this example, the script will automatically timeout after 10 seconds, throwning a &lt;em&gt;TimeoutException&lt;/em&gt;. Apart from the two previously described annotation parameters, this annotation accepts two additional ones :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;value&lt;/em&gt; (mandatory, defaults to 1) : the amount of time unit the script is allowed to consume&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;unit&lt;/em&gt; (defaults to TimeUnit.SECONDS) : the unit used to describe the timeout&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_conditionalinterrupt&quot;&gt;@ConditionalInterrupt&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This one is another powerful variant of automatic thread interruption annotation. It allows the user to provide a custom condition for interruption. For example, one would like to check that user credentials are valid, while other would like to ensure that there are enough file descriptors left to allow script execution. There’s a wide variety of problems that can be solved thanks to this one. In my examples, I’ll focus on simple test cases to show off the advantages of this annotation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@ConditionalInterrupt({counter++&amp;gt;1})
import groovy.transform.ConditionalInterrupt

counter=0
def scriptMethod() {
     4.times {
         println &apos;executing script method...&apos;
     }
}

scriptMethod()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this example, the @ConditionalInterrupt annotation accepts a &lt;em&gt;closure as annotation value&lt;/em&gt;. This amazing features which is already used by &lt;a href=&quot;https://github.com/andresteingress/gcontracts&quot;&gt;GContracts&lt;/a&gt; allows us to annotate a class (or import statement) with a custom condition. Here, we implement a custom interruption policy which decides that an &lt;em&gt;InterruptedException&lt;/em&gt; should be thrown whenever &lt;em&gt;counter1&lt;/em&gt;. The &lt;em&gt;counter&lt;/em&gt; variable references the one defined in the script. This is the main difficulty you’ll have to face with this annotation : variable scoping. The semantics is not different from the one in regular Groovy scripts, but may be hard to understand. Indeed, replacing the line :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;counter=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;with&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def counter=0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;would cause the compilation to fail because the counter variable would not be in the scope. Now the hard question is given the annotated script upper, how many times would you expect the `executing script method…&apos; message to be displayed ? If your answer is 2, not bad, but you missed one point. If your answer is 1, either you are lucky, or you are brilliant. If your answer is anything else, you’ll be interested in the explanation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;How is this script updated ? To check it out, you can use the AST Browser found in the Groovy console. It will show you how your script gets transformed, and help you tune your custom conditions. Here, the generated script looks like this (stripped for clarity) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class script1291150384631 extends groovy.lang.Script {

    public java.lang.Object run() {
        counter = 0
        this.scriptMethod()
    }

    public java.lang.Object scriptMethod() {
        if (this.conditionalTransform$condition()) {
            throw new java.lang.InterruptedException(&apos;Execution Interrupted&apos;)
        }
        4.times({
            if (this.conditionalTransform$condition()) {
                throw new java.lang.InterruptedException(&apos;Execution Interrupted&apos;)
            }
            this.println(&apos;executing script method...&apos;)
        })
    }

    protected java.lang.Boolean conditionalTransform$condition() {
        ( counter )++ &amp;gt; 1
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Got it ? If your answer was two, you probably missed the fact that &lt;em&gt;scriptMethod&lt;/em&gt; first statement will be, by default (understand unless you set the &lt;em&gt;checkOnMethodStart&lt;/em&gt; flag to false), an interruption check…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Can we do anything more complex with it ? Indeed, you can. For example, I can imagine, in a web application, a custom condition that would use a helper class which looks up a thread local to extract the current request context and check user credentials. Here’s another example which demonstrates a very simple case where the condition is shared by multiple classes :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.transform.ConditionalInterrupt

class Helper {
  static int i=0
  static def shouldInterrupt() { i++&amp;gt;0 }
}

@ConditionalInterrupt({ Helper.shouldInterrupt() })
class MyClass {
   def myMethod() { }
}

class MyOtherClass {
   def myOtherMethod() { new MyClass().myMethod() }
}

new MyOtherClass().myOtherMethod()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, a Helper class stores a static counter. Every method call will increase the counter, independently of the class from which a method is called. A few tricks to understand though :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;we are using static members for the helper class (both counter and method) because this annotation &lt;strong&gt;does not&lt;/strong&gt; add interrupt checks on static members. If it had, then the Helper class itself would have been modified, and you would have ended with a stack overflow error.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;it is not necessary to add the annotation to the second class as by default, the &lt;em&gt;applyToAllClasses&lt;/em&gt; flag is on&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_few_gotchas&quot;&gt;A few gotchas&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There is something more you need to be aware when using this annotation : first, it’s obvious (yet we talk about it) that this won’t deal with pure Java classes that the script may use. If an infinite loop occurs in a Java library used by the script, it won’t get interrupted. Second, you must take care of open resources, especially files, sockets, result sets, … that would not be closed if the script didn’t check for exceptions. Those magic annotations won’t do it for you.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I really hope you’ll enjoy those new features, as I think those are quite mandatory in production environments where Groovy scripts are not totally under control (this is not limited to user errors, but resources exhausted is a common case too).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Using custom Groovy metaclasses to boost performance</title>
      <link>https://melix.github.io/blog//2010/11/10/using_custom_groovy_metaclasses_to.html</link>
      <pubDate>Wed, 10 Nov 2010 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2010/11/10/using_custom_groovy_metaclasses_to.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy is a dynamic language by nature. This means, in Groovy, that method dispatches are controlled by metaclasses. This is really powerful, and allows nice tricks like the &lt;code&gt;method missing&apos;&apos; or &lt;/code&gt;property missing&apos;&apos; calls that are used in many DSLs. The metaclass dictates what behaviour is expected whenever a call to a property or a method is made.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The ``problem&apos;&apos; with this is that method execution paths may be really long. Though Groovy uses call site caching to improve performance, the chain of invocation to call a method in Groovy is much, much longer than in plain Java. The only reason why this chain is long is to allow that dynamic behaviour.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, when performance is critical and that you still want to use Groovy as a DSL, there are not so many things you can do to improve performance :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;coding critical parts in Java and using mixed compilation to call Java classes&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;use profilers to hunt down slow parts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today, I’ll add a nice one that I’ve just experienced : &lt;strong&gt;using custom metaclasses&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_explanation&quot;&gt;The explanation&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To simplify, almost every method call you make in Groovy will end up beeing dispatched by the class called &lt;em&gt;MetaClassImpl&lt;/em&gt;. This class manages a wide variety of method calls or property access. It deals with closures as well as ``regular objects&apos;&apos;. We’ll take, as an example, the body of the &lt;em&gt;MetaClassImpl#invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass)&lt;/em&gt; method :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;checkInitalised();
        if (object == null) {
            throw new NullPointerException(&quot;Cannot invoke method: &quot; + methodName + &quot; on null object&quot;);
        }

        final Object[] arguments = originalArguments == null ? EMPTY_ARGUMENTS : originalArguments;
//        final Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
//
//        unwrap(arguments);

        MetaMethod method = getMethodWithCaching(sender, methodName, arguments, isCallToSuper);
        MetaClassHelper.unwrap(arguments);

        if (method == null)
            method = tryListParamMetaMethod(sender, methodName, isCallToSuper, arguments);

        final boolean isClosure = object instanceof Closure;
        if (isClosure) {
            final Closure closure = (Closure) object;

            final Object owner = closure.getOwner();

            if (CLOSURE_CALL_METHOD.equals(methodName) || CLOSURE_DO_CALL_METHOD.equals(methodName)) {
                final Class objectClass = object.getClass();
                if (objectClass == MethodClosure.class) {
                    final MethodClosure mc = (MethodClosure) object;
                    methodName = mc.getMethod();
                    final Class ownerClass = owner instanceof Class ? (Class) owner : owner.getClass();
                    final MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
                    return ownerMetaClass.invokeMethod(ownerClass, owner, methodName, arguments, false, false);
                } else if (objectClass == CurriedClosure.class) {
                    final CurriedClosure cc = (CurriedClosure) object;
                    // change the arguments for an uncurried call
                    final Object[] curriedArguments = cc.getUncurriedArguments(arguments);
                    final Class ownerClass = owner instanceof Class ? (Class) owner : owner.getClass();
                    final MetaClass ownerMetaClass = registry.getMetaClass(ownerClass);
                    return ownerMetaClass.invokeMethod(owner, methodName, curriedArguments);
                }
                if (method==null) invokeMissingMethod(object,methodName,arguments);
            } else if (CLOSURE_CURRY_METHOD.equals(methodName)) {
                return closure.curry(arguments);
            }

            final Object delegate = closure.getDelegate();
            final boolean isClosureNotOwner = owner != closure;
            final int resolveStrategy = closure.getResolveStrategy();

            final Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);

            switch (resolveStrategy) {
                case Closure.TO_SELF:
                    method = closure.getMetaClass().pickMethod(methodName, argClasses);
                    if (method != null) return method.invoke(closure, arguments);
                    break;
                case Closure.DELEGATE_ONLY:
                    if (method == null &amp;amp;&amp;amp; delegate != closure &amp;amp;&amp;amp; delegate != null) {
                        MetaClass delegateMetaClass = lookupObjectMetaClass(delegate);
                        method = delegateMetaClass.pickMethod(methodName, argClasses);
                        if (method != null)
                            return delegateMetaClass.invokeMethod(delegate, methodName, originalArguments);
                        else if (delegate != closure &amp;amp;&amp;amp; (delegate instanceof GroovyObject)) {
                            return invokeMethodOnGroovyObject(methodName, originalArguments, delegate);
                        }
                    }
                    break;
                case Closure.OWNER_ONLY:
                    if (method == null &amp;amp;&amp;amp; owner != closure) {
                        MetaClass ownerMetaClass = lookupObjectMetaClass(owner);
                        return ownerMetaClass.invokeMethod(owner, methodName, originalArguments);
                    }
                    break;
                case Closure.DELEGATE_FIRST:
                    if (method == null &amp;amp;&amp;amp; delegate != closure &amp;amp;&amp;amp; delegate != null) {
                        MetaClass delegateMetaClass = lookupObjectMetaClass(delegate);
                        method = delegateMetaClass.pickMethod(methodName, argClasses);
                        if (method != null)
                            return delegateMetaClass.invokeMethod(delegate, methodName, originalArguments);
                    }
                    if (method == null &amp;amp;&amp;amp; owner != closure) {
                        MetaClass ownerMetaClass = lookupObjectMetaClass(owner);
                        method = ownerMetaClass.pickMethod(methodName, argClasses);
                        if (method != null) return ownerMetaClass.invokeMethod(owner, methodName, originalArguments);
                    }
                    if (method == null &amp;amp;&amp;amp; resolveStrategy != Closure.TO_SELF) {
                        // still no methods found, test if delegate or owner are GroovyObjects
                        // and invoke the method on them if so.
                        MissingMethodException last = null;
                        if (delegate != closure &amp;amp;&amp;amp; (delegate instanceof GroovyObject)) {
                            try {
                                return invokeMethodOnGroovyObject(methodName, originalArguments, delegate);
                            } catch (MissingMethodException mme) {
                                if (last == null) last = mme;
                            }
                        }
                        if (isClosureNotOwner &amp;amp;&amp;amp; (owner instanceof GroovyObject)) {
                            try {
                                return invokeMethodOnGroovyObject(methodName, originalArguments, owner);
                            } catch (MissingMethodException mme) {
                                last = mme;
                            }
                        }
                        if (last != null) return invokeMissingMethod(object, methodName, originalArguments, last, isCallToSuper);
                    }

                    break;
                default:
                    if (method == null &amp;amp;&amp;amp; owner != closure) {
                        MetaClass ownerMetaClass = lookupObjectMetaClass(owner);
                        method = ownerMetaClass.pickMethod(methodName, argClasses);
                        if (method != null) return ownerMetaClass.invokeMethod(owner, methodName, originalArguments);
                    }
                    if (method == null &amp;amp;&amp;amp; delegate != closure &amp;amp;&amp;amp; delegate != null) {
                        MetaClass delegateMetaClass = lookupObjectMetaClass(delegate);
                        method = delegateMetaClass.pickMethod(methodName, argClasses);
                        if (method != null)
                            return delegateMetaClass.invokeMethod(delegate, methodName, originalArguments);
                    }
                    if (method == null &amp;amp;&amp;amp; resolveStrategy != Closure.TO_SELF) {
                        // still no methods found, test if delegate or owner are GroovyObjects
                        // and invoke the method on them if so.
                        MissingMethodException last = null;
                        if (isClosureNotOwner &amp;amp;&amp;amp; (owner instanceof GroovyObject)) {
                            try {
                                return invokeMethodOnGroovyObject(methodName, originalArguments, owner);
                            } catch (MissingMethodException mme) {
                                if (methodName.equals(mme.getMethod())) {
                                    if (last == null) last = mme;
                                } else {
                                    throw mme;
                                }
                            }
                            catch (InvokerInvocationException iie) {
                                if (iie.getCause() instanceof MissingMethodException) {
                                    MissingMethodException mme = (MissingMethodException) iie.getCause();
                                    if (methodName.equals(mme.getMethod())) {
                                        if (last == null) last = mme;
                                    } else {
                                        throw iie;
                                    }
                                }
                                else
                                  throw iie;
                            }
                        }
                        if (delegate != closure &amp;amp;&amp;amp; (delegate instanceof GroovyObject)) {
                            try {
                                return invokeMethodOnGroovyObject(methodName, originalArguments, delegate);
                            } catch (MissingMethodException mme) {
                                last = mme;
                            }
                            catch (InvokerInvocationException iie) {
                                if (iie.getCause() instanceof MissingMethodException) {
                                    last = (MissingMethodException) iie.getCause();
                                }
                                else
                                  throw iie;
                            }
                        }
                        if (last != null) return invokeMissingMethod(object, methodName, originalArguments, last, isCallToSuper);
                    }
            }
        }

        if (method != null) {
            return method.doMethodInvoke(object, arguments);
        } else {
            return invokePropertyOrMissing(object, methodName, originalArguments, fromInsideClass, isCallToSuper);
        }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, before you get a headache, you’ll just focus on one thing : most of this code deals with the &lt;em&gt;Closure&lt;/em&gt; case. What if your class is not a closure ? I guess that’s true for about 90% of method calls. For example, in the following code :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def myObject = new MySuperFastJavaObject()
myObject.mySuperFastMethod()&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here, you just want the method call to behave exactly as if it were made from pure Java. If you don’t write a custom metaclass, the metaclass that will be used by Groovy will dispatch your method call through the upper algorithm. You have understood that there’s no need to deal with the closure case here. So, you could write your own metaclass that removes everything from the closure case in the invokeMethod method :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package groovy.runtime.metaclass.com.mypackage;

public class MySuperFastJavaObjectMetaClass extends MetaClassImpl {
 ...
        @Override
 public Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
  checkInitalised();
  if (object == null) {
   throw new NullPointerException(&quot;Cannot invoke method: &quot; + methodName + &quot; on null object&quot;);
  }

  final Object[] arguments = originalArguments == null ? EMPTY_ARGUMENTS : originalArguments;
  MetaMethod method = getMethodWithCaching(sender, methodName, arguments, isCallToSuper);
  MetaClassHelper.unwrap(arguments);

  if (method != null) {
   return method.doMethodInvoke(object, arguments);
  } else {
   return invokeMissingMethod(object, methodName, arguments);
  }
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Several things to notice :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;usage of the &lt;em&gt;groovy.runtime.metaclass&lt;/em&gt; prefix in your package will guarantee that Groovy will automatically load your metaclass and assign it to your class&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the name of your metaclass is the name of your class plus the &lt;em&gt;MetaClass&lt;/em&gt; suffix&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;overriding some methods only can lead to huge performance improvements&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now, say your object doesn’t require dynamic behaviour like &lt;em&gt;methodMissing&lt;/em&gt;. Why would you end up calling the &lt;em&gt;invokeMissingMethod&lt;/em&gt; method ? If you take a closer look at this method, you’ll notice that the default implementation does many things, and, in your case, will &lt;strong&gt;always&lt;/strong&gt; fail since you don’t have defined any &lt;em&gt;methodMissing&lt;/em&gt; method. That’s really a waste of time. So you can directly replace it with a missing method exception :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package groovy.runtime.metaclass.com.mypackage;

public class MySuperFastJavaObjectMetaClass extends MetaClassImpl {
 ...
        @Override
 public Object invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass) {
  checkInitalised();
  if (object == null) {
   throw new NullPointerException(&quot;Cannot invoke method: &quot; + methodName + &quot; on null object&quot;);
  }

  final Object[] arguments = originalArguments == null ? EMPTY_ARGUMENTS : originalArguments;
  MetaMethod method = getMethodWithCaching(sender, methodName, arguments, isCallToSuper);
  MetaClassHelper.unwrap(arguments);

  if (method != null) {
   return method.doMethodInvoke(object, arguments);
  } else {
   throw new new MissingMethodException(methodName, sender, arguments);
  }
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that I also had the opposite case : if I were on a missing method, the target method in my Java class was always the same. So I could hijack the meta-object protocol so that it doesn’t try a tons of things before dispatching to &lt;strong&gt;always&lt;/strong&gt; the same method missing implementation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@Override
 public Object invokeMissingProperty(final Object instance, final String propertyName, final Object optionalValue, final boolean isGetter) {
  Layer layer = (Layer) instance; // Layer metaclass, it&apos;s ALWAYS a Layer
         return layer.java_propertyMissing(propertyName);
 }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another case was dealing with the following bug (?) : &lt;a href=&quot;https://jira.codehaus.org/browse/GROOVY-4495&quot; class=&quot;bare&quot;&gt;https://jira.codehaus.org/browse/GROOVY-4495&lt;/a&gt;. In a specific case, static method invocation always lead to the longest execution path possible. However, in my case, the class used is an utility class which inherits another, the two written in pure Java, and for which every method is static. In another words, it’s a toolbox. Why would I want dynamic method dispatching on this class ? There’s no reason. So, I implemented my own metaclass which directly delegated calls to the appropriate methods AND worked around the bug by adding the method defined by the parent class in the method cache.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_expected_improvements&quot;&gt;Expected improvements&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, doing this, how much improvement can you expect ? Well, I’ll talk about my case. As I’ve already said, the critical parts of code are all written in pure Java. So most of Groovy is used as a DSL. After having added a single metaclass, I reached a 10% improvement in execution time. I was so surprised by the result that I added a few metaclasses, and I reached up to 25% execution time improvement depending on the application. The only thing I can say is that it is really important to take this in consideration when you want to make the best of Groovy. Try it yourself !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Experience feedback on Groovy</title>
      <link>https://melix.github.io/blog//2010/07/27/experience_feedback_on_groovy.html</link>
      <pubDate>Tue, 27 Jul 2010 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2010/07/27/experience_feedback_on_groovy.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;(lecteurs francophones, vous pouvez consulter la &lt;a href=&quot;https://www.jroller.com/melix/entry/retour_d_exp%C3%A9rience_groovy&quot;&gt;version française ici&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;On the occasion of the 3rd anniversary of this blog, I wanted to write a special post. It appears that it will be special in two ways. First, it’s the first one to be published in both French and English. Second, this article is about a language which slowly took a large place in my everyday work for the last years, I mean Groovy. I hope this post will interest you, and will help those who hesitate on using this language industrially to make their choice : I’ll try to show off the pros and cons, and as usual, discussion is open : I encourage you to write comments. I will focus on the industrial consequences of choosing Groovy more than the technical issues, though both are related.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_once_upon_a_time&quot;&gt;Once upon a time&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Groovy adoption at Lingway wasn’t made in one day. I joined the team in a special circumstance, as the company I was working for was bought by Lingway. At this time, we already used to integrate scripting languages to allow easier customizations, but their usage was rather limited. I had made the choice to integrate both Mozilla Rhino and BeanShell, but not Groovy. Why ? Well the reason is quite simple : I had missed it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At Lingway, in the context of rewriting Perl components to Java and improving them, I was driven by the idea of using scripting languages to make things easier to customize. Particularly, there were two main use cases :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the need to parametrize data acquisition workflows for our main product, Lingway Knowledge Management&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the design of a new content extraction engine for documents written in natural language&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It was by that time, reading posts about &lt;em&gt;closures&lt;/em&gt; (the lack of) in Java that I discovered Groovy. It was the beginning of a long love story ! What Groovy allowed to do perfectly suited my requirements :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a language on the JVM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;able to use Java libraries, and, very important, usable from Java libraries (also known as cross compilation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a dynamic language supporting closures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ability to write DSLs (Domain Specific Languages)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a clear and simple syntax which would allow people not aware of development to write scripts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Those two use cases, which lead to a global adoption of Groovy in our components/products, will allow me to illustrate the pros and cons of this language in an industrial context.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_syntax_matters&quot;&gt;Syntax matters&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If there were one thing to highlight as a key factor of Groovy’s adoption, it would definitely be syntax. Groovy offerts over other JVM languages like Scala or Clojure, major advantages :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a syntax 95%-compatible with Java : it greatly reduces the learning curve since any Java developer will be able to code in Groovy without having to know nor understand the subtleties of this language. In a reduced team where there’s not much time allowed for learning, it is very important.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;precious add-ons : utility methods/classes which simplifies the usage of standard JDK Apis and makes code more compact&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;usage of closures, which allows us to focus on algorithmics more than syntax&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a dynamic type system, which allows newbies to avoid thinking about types&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s come back on the last point : I have already said that I planned to use Groovy in edge cases where &lt;code&gt;users&apos;&apos; were not &lt;/code&gt;computer aware&apos;&apos;. While this term is quite unfair, it does hide what I consider now as a great success in the introduction of Groovy. The challenge was dared, but it worked : at Lingway, we have three profile types in our technical team : first, developers - like me -, coming from software engineering. Second, consultants, who are trained for programming, but have lower pure technical skills : their main abilities are transforming customer needs into parametrization. Those are the people who write our workflows. Last but not least, linguists, who for most only know about computers as tools : they don’t know anything about programming languages and software engineering. However, thanks to Groovy, all those three profiles are able to collaborate on a single platform, a single language. The ability for Groovy to simplify at most syntax and the ability to create DSLs is amazing.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Let’s take a real example, in the context of acquisition workflows A java programmer would have written (correctly) the following :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Map inputMap = new HashMap()
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Title, &quot;Hello, World !&quot;);
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Body,&quot;Groovy is cool !&quot;);
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Language,com.lingway.lkm.db.corpus.bean.languages.LanguageKind.ENGLISH);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Usage of Groovy in workflows allows us to simplify it to :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;inputMap = [
   title: &quot;Hello, World !&quot;
   body: &quot;Groovy is cool !&quot;
   language: &quot;en&quot;
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This way of doing allows the workflow ``code&apos;&apos; to be much more readable. It allows us to focus on what to do, not on how to do. This is extremely important and allows us to save time : it is easier to read and maintain. Moreover, it is not required to be an expert to understand what it does : no need to know what a HashMap is. No need to even know that you actually need to instanciate one. Let’s see another example where we would like to sum up the numbers contained in a flat file (one number per line). Our Java developper would have written the following :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;File file = new File(&quot;/tmp/data.txt&quot;);
int total = 0;
try {
 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), &quot;utf-8&quot;));
 String line;
 while ((line=reader.readLine())!=null) {
  if (line.length()&amp;gt;0) total += Integer.valueOf(line);
 }
 reader.close();
} catch (IOException e) {
 // this must never happen, and if it does, I don&apos;t know what to do
}
System.out.println(&quot;total = &quot; + total);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In Groovy, you’d just write this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def total = 0
new File(&quot;/tmp/data.txt&quot;).eachLine(&quot;utf-8&quot;) { line -&amp;gt;
   if (line) total += line as int
}
println &quot;Total : $total&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;From 13 lines, we fall to 4. Those 4 lines only focus on what to do. At worse, you’ll have to explain to your interlocutor what &lt;em&gt;eachLine&lt;/em&gt; or &lt;em&gt;as int&lt;/em&gt; does, and you’re done. Likely, Groovy is the perfect candidate for simplifying the usage of Java APIs. One of my favorite example is taken from the Gaelyk documentation, a simplified web framework based on Groovy :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;mail.send sender: &quot;app-admin-email-AT-gmail-DOT-com&quot;,
   to: &quot;recipient-AT-somecompany-DOT-com&quot;,
   subject: &quot;Hello&quot;,
   textBody: &quot;Hello, how are you doing? -- MrG&quot;,
   attachment: [data: &quot;Chapter 1, Chapter 2&quot;.bytes, fileName: &quot;outline.txt&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s an example of a ``mini-DSL&apos;&apos;, dedicated to sending e-mails. How could one imagine something simpler ? When you actually know about the verbosity of the Javamail API, it’s no match…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, thanks to Groovy’s adaptability, we were able to :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;make our workflows readable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;write a DSL dedicated to linguistic extraction rules. This language is the core of our internal data extraction tool, and is mainly used by our linguists&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;About that, the strengths of Groovy in such a tool are multiple :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;it allows non developers to write rules which are compiled to bytecode then executed by the JVM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;when the DSL is not sufficient, linguists may ask the developers for help. The latter would then write chunks of Groovy code which perform complex operations&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, what is possible is not limited to what the DSL allows. It is something particularly important to understand : if we had chosen to write a classical DSL, a rule based engine which would use its own syntax, then we would probably have achieved a higher level of readability, but we would also have had to :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;either write an interpreter (simple solution) or a compiler (complex one) for our rules&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;develop new versions of the language as new needs are discovered&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With Groovy, you just skip those steps, and you just earn an extra : it’s just code. Even if linguists actually write rules, there’s nothing that prevents us from writing regular code inside. The whole language is usable…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A funny thing is that as time passes by, linguists show an increasing curiosity towards the ``code&apos;&apos; part of rules. They naturally aim at factorizing rules : the language becomes structuring and leads to better code quality !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_barriers&quot;&gt;The barriers&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So far I’ve been particularly enthusiast about Groovy. However, it’s not that simple, and there are things that are get complicated. I’ll split the barriers into two categories : technical barriers and humain barriers. Don’t neglect any of them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_technical_barriers&quot;&gt;Technical barriers&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The first technical barrier we encountered was performance. Release after release, Groovy becomes faster and I can tell you that the current versions are really fast. However, don’t expect miracles. In particular, in the context of our extraction engine, we had a very important performance expectation. The objective, for example, was to be able to perform a complete resume parsing and data extraction (name, surname, personal data, experiences, trainings, …) from a binary document (Word,…) within a second. If the core of our engine had been written in Groovy, there’s no chance that we could have reached such a performance. That’s why we decided to write the critical parts in pure Java, while the domain code is written in Groovy (leading to a DSL). This way we have a good trade-off between performance and readability.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So, if writing code in Groovy is really easy thanks to its syntax, it is just also easy to write slow code. I remember a parser written in Groovy which read the XML configuration file of our engine. This code was written in Groovy because the &lt;em&gt;XmlSlurper&lt;/em&gt; makes it really easy to read XML files. Whatever, the Java code was 20 times as fast as the Groovy version… (admittedly, almost 20 times longer). Another example about the curious default type used by Groovy in decimal computations :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def num = 1.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The type associated to &lt;em&gt;num&lt;/em&gt; is not, as one would expect, &lt;em&gt;float&lt;/em&gt; nor &lt;em&gt;double&lt;/em&gt;, it’s &lt;em&gt;BigDecimal&lt;/em&gt;. As a direct consequence, every benchmark found on the web about Groovy falls into this trap. You just have to strongly type your code to make performance acceptable (and more). For a language which simplifies life by avoiding strong typing, it seems curious and just mystifies the principal of least surprise (for the curious, there’s an explanation for that, as the Groovy developers chose to apply the principal of least surprise to the result of computations more than on the types : using &lt;em&gt;BigDecimal&lt;/em&gt; allows computations to be exact).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using Groovy code from Java leads to another barrier : since the natural way of coding in Groovy is to weakly type, Groovy generated APIs only take &lt;em&gt;Object&lt;/em&gt; as parameters. Those APIs are just unusable, so if your Groovy code is intended to be used from Java, you’ll have to make the effort to strongly type.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Another barrier is directly related to the global adoption of Groovy in the technical team. The success of Groovy makes that we wish to introduce it everywhere. However, when different components include different versions of Groovy, you take the risk of compatibility issues. Happily, unlike the Scala language for example, Groovy maintains binary compatibility between one version and another. I greatly reduces the risks when upgrading.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_human_barriers&quot;&gt;Human barriers&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Curiously, the main barriers encountered during the adoption of Groovy were not technical but humain. And more curiously, the ones I faced did not come from people I expected. I expected linguists to rebel, it were developers !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To understand properly, you must understand that developers are Lingway all have nearly 10 years of experience. I can modestly say that they are good (if not very) developers. As good developers, they use good tools : I cannot understand when people use &lt;em&gt;vi&lt;/em&gt; or &lt;em&gt;Emacs&lt;/em&gt; to code : the main strength of Java has never been the language, but rather its tools. At Lingway, we use &lt;em&gt;IntelliJ IDEA&lt;/em&gt;. This IDE is for me the best IDE available on the market for Java development. We’ve used it for long, and getting back to Eclipse would be worse than a curse for us. With a strongly types language like Java, and even more with the addition of generics, code is understandable (but rather noisy) : you actually know, reading the code, that this collection actually contains that type of objects. The compiler will complain if you try to use different content, and if you use an intelligent IDE, without having to compile, it will indicate to you what are the possible choices for what method, depending on the context. As time goes, the programmer develops what I call the ``completion frenzy&apos;&apos; : you actually pass most of your time pressing the CTRL+space or CTRL+Q key combinations. It’s no use to read javadoc, since my IDE will gently indicate me what the method expects at what position. When you intensively practice that, you may reach an incredible productivity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In that context, the transition to Groovy looks like a regression : being widely sub-typed (and I’m fighting to make understand that weakly typed doesn’t mean untyped), it’s most of time impossible to know what a method/closure/map expects as a parameter without reading the documentation. However, when we come to documentation, we can find the best, like the worse. Even your IDE is useless : it doesn’t have enough hints to help you. Most of CTRL+space calls are headed for failure : it leads to an incredible frustration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, developers just tend to come back the natural way : Java developers ``Java-ize&apos;&apos; their code, instead of Groovyfying it. We loose readability for ease of development. It’s quite paradoxical and I try to fight against this, but it’s difficult to challenge : I just think that unless you are a very curious and open developer, you’ll find it frustrating to fly visually. It’s just like getting 10 years back.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I must admit I have not succeeded to perfectly initiate the Groovy spirit to the team. Some make resist while others make efforts but it’s a question of feeling first : it’s very hard to fight against natural tendencies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Recently, we started using &lt;em&gt;Grails&lt;/em&gt; for an application of e-reputation analysis. This development is still in progress, and once again, I made a bet to try to developer faster. For now, I’m really satisfied of the result which leads to an unprecedented productivity. However, frustrations are not gone : the IDE support is far from perfect and widely insufficient : almost no completion, no differentiation between dynamic methods which are added by default to every object and service methods, for example. There’s not much more completion for &lt;em&gt;render&lt;/em&gt; parameters. For &lt;em&gt;taglibs&lt;/em&gt;, the standard completion is insufficient and there’s no way for the IDE to actually help because Grails taglibs definition miss metadata about required attributes and so on. You just actually have to open multiple Grails help web pages to get it right.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conlusion&quot;&gt;Conlusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Through this post, I tried to show off the industrial usage of Groovy, integrated in many components which actually are in production (in our case, for more than 3 years). The global balance is positive, but you really don’t have to neglect the barriers of the integration of Groovy. Particularly, Groovy doesn’t escape one of the most complicated activities : driving change. A programmer which is too comfortable with Java will have difficulties to embrace the language and will sometimes be awfully insincere just to justify his own choices, guided by personal comfort : scarifying readability for tools. This is not unjustifiable, since I often find myself cursing the lack of completion from my IDE. This is not enough to change my mind about Groovy : this is surely one of the best thing that happened to Java for the last 10 years… A language to recommand, and I hope it’ll spread widely !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;(for my english-speaking audience, my english is not perfect, do not hesitate to correct me)&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Retour d&amp;#8217;expérience : Groovy</title>
      <link>https://melix.github.io/blog//2010/07/26/retour_d_exp%C3%A9rience_groovy.html</link>
      <pubDate>Mon, 26 Jul 2010 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2010/07/26/retour_d_exp%C3%A9rience_groovy.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;(english speakers may read the &lt;a href=&quot;https://www.jroller.com/melix/entry/experience_feedback_on_groovy&quot;&gt;english version here&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A l’occasion des trois ans de ce blog, je souhaitais écrire un billet un peu spécial. Il le sera à double titre, puisque tout d’abord publié en deux langues et ensuite parce que consacré à un retour d’expérience sur un langage qui a pris énormément d’importance dans mon travail ces dernières années : Groovy. J’espère que cet article vous intéressera, et aidera celles et ceux qui hésitent à employer ce langage daniqs leur entreprise à faire leur choix : je dresserai aussi bien les aspects positifs de son utilisation que ceux négatifs. Par ailleurs, comme toujours, la discussion est ouverte, et je vous invite à réagir en écrivant en commentaire. Mon objectif est de centrer ce retour sur l’utilisation industrielle de Groovy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_un_peu_dhistoire&quot;&gt;Un peu d’histoire&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L’adoption de Groovy chez Lingway ne s’est pas faite en un jour. J’ai intégré cette entreprise d’une manière assez particulière, puisque l’entreprise pour laquelle je travaillais s’est faite rachetée par Lingway. A cette époque, nous utilisions déjà des langages dits de scripting pour faciliter la personnalisation de nos produits. Leur utilisation était alors très limitée. J’avais fais le choix d’utiliser Mozilla Rhino et BeanShell. Pourquoi pas Groovy ? Tout simplement parce que je n’avais pas entendu parler de ce langage.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Arrivé chez Lingway, la réécriture de nombreux composants Perl vers Java et l’amélioration de ceux-ci m’ont poussé à creuser l’idée de l’utilisation de langage de scripts pour la personnalisation de l’application aux besoins utilisateurs. En particulier, deux cas d’utilisation distincts :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;la nécessité de paramétrer des workflows d’acquisition de données pour l’indexation de documents dans notre produit, Lingway Knowledge Management&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;l’écriture d’un nouveau moteur d’extraction de données textuelles dans les documents en langue naturelle&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cet à ce moment qu’au détour de lectures sur les &lt;em&gt;closures&lt;/em&gt; en Java (ou plutôt, l’absence de &lt;em&gt;closures&lt;/em&gt;), je fis la découverte de Groovy. Ce fut le début d’une longue histoire d’amour ! Ce que permettait Groovy correspondait exactement à mon besoin :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;un langage fonctionnant sur la JVM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;qui puisse appeler des librairies Java, et qui, très important, puisse en retour être appelé depuis Java&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un langage dynamique supportant les closures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;la possibilité de créer des DSL (Domain Specific Languages)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;une syntaxe simple, permettant à des non informaticiens d’apprendre et d’écrire des scripts&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Les deux cas d’utilisation principaux, qui ont mené à l’adoption générale de Groovy dans de nombreux composants/produits, vont me permettre d’illustrer les avantages et les inconvénients de ce langage, dans un contexte industriel.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_la_syntaxe_est_importante&quot;&gt;La syntaxe est importante&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;S’il y a un élément que je dois mettre en avant comme étant l’élément clé de l’adoption de Groovy dans l’entreprise, c’est bien celui de la syntaxe. Groovy offre, par rapport à d’autres langages sur la JVM comme Scala ou Clojure, des avantages immenses :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;syntaxe à 95% compatible Java : n’importe quel développeur Java peut écrire du Groovy, sans avoir besoin de comprendre les particularités de ce langage : celà permet d’avoir un temps d’apprentissage extrêmement réduit. Lorsque dans une équipe, on n’a pas beaucoup de temps à consacrer à la formation, c’est un plus indéniable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;des ajouts précieux : l’ajout de nombreuses méthodes ``utilitaires&apos;&apos; simplifiant l’utilisation des API standard rend le code plus compact&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;l’utilisation des closures, qui permettent de se concentrer sur l’algorithmique avant la syntaxe&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;un typage dynamique, qui permet aux non initiés d’éviter d’avoir à se poser la question des types&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Revenons sur ce dernier point. A plusieurs reprises, j’ai fait référence à la possibilité d’utiliser Groovy pour faire travailler des ``non informaticiens&apos;&apos;. Si le terme est un peu abusif, il n’en résume pas moins ce que je considère avec le recul comme une grande réussite. Le pari était osé, mais il a fonctionné : chez Lingway, nous avons trois types de profils dans l’équipe de développement. Il y a d’abord les développeurs, comme moi, issus de formations en ingénierie informatique. Ensuite, nous trouvons les consultants, qui s’ils sont formés à l’informatique et au développement, ont un niveau de technicité moins élevé : leur expertise repose sur la compréhension du besoin client et au paramétrage de nos produits. En particulier, ce sont eux qui écrivent les fameux workflows d’acquisition. Enfin, la dernière catégorie correspond aux linguistes. S’ils sont formés à l’informatique, c’est avant tout en tant qu’outil : la plupart d’entre eux ne connaissent rien des langages de programmation. Pourtant, grâce à Groovy, ces trois profils peuvent cohabiter sur une même plateforme, un même langage. La capacité qu’on a, avec Groovy, de simplifier à l’extrême la syntaxe, et à écrire des langages de domaine est extraordinaire.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Prenons un exemple concret, dans le cadre des workflows d’acquisition de données. L’ingénieur Java, sans Groovy, aurait écrit ceci (et il aurait bien fait son travail) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Map inputMap = new HashMap()
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Title, &quot;Hello, World !&quot;);
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Body,&quot;Groovy is cool !&quot;);
inputMap.put(com.lingway.lkm.db.corpus.bean.fields.DublinExtendedKind.Language,com.lingway.lkm.db.corpus.bean.languages.LanguageKind.ENGLISH);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;L’utilisation de Groovy dans nos workflows permet de simplifier l’écriture ainsi :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;inputMap = [
   title: &quot;Hello, World !&quot;
   body: &quot;Groovy is cool !&quot;
   language: &quot;en&quot;
]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Cette façon de faire permet de rendre le code du workflow beaucoup plus lisible, et de se concentrer sur ce que doit faire le workflow, non sur la syntaxe. C’est extrêmement important, et ça permet de gagner énormément de temps : la lecture est facilitée, la maintenance aussi. Par ailleurs, il n’y a pas besoin d’une expertise énorme pour comprendre ce que celà fait. Pas besoin de comprendre de qu’est une hashmap. Pas besoin de savoir, même, qu’il faut en créer une… Un autre exemple, concernant la lecture d’un fichier ligne par ligne sur lequel on souhaiterait faire la somme des entiers qu’il contient: notre développeur Java aurait écrit ceci :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;File file = new File(&quot;/tmp/data.txt&quot;);
int total = 0;
try {
 BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), &quot;utf-8&quot;));
 String line;
 while ((line=reader.readLine())!=null) {
  if (line.length()&amp;gt;0) total += Integer.valueOf(line);
 }
 reader.close();
} catch (IOException e) {
 // this must never happen, and if it does, I don&apos;t know what to do
}
System.out.println(&quot;total = &quot; + total);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;En groovy, on se contentera d’écrire ceci :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def total = 0
new File(&quot;/tmp/data.txt&quot;).eachLine(&quot;utf-8&quot;) { line -&amp;gt;
   if (line) total += line as int
}
println &quot;Total : $total&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;De 13 lignes, on passe à 4. Ces 4 lignes se concentrent sur la seule chose qui importe : le traitement. Au pire, vous devrez expliquer à votre interlocuteur novice en Groovy ce que fait &lt;em&gt;eachLine&lt;/em&gt; ou &lt;em&gt;as int&lt;/em&gt;, et tout est compris… De la même façon, Groovy est un excellent outil pour simplifier l’utilisation des API Java. Un des exemples qui me plaît le plus est celui de l’utilisation de l’API Java mail (tiré de la documentation de &lt;a href=&quot;&quot;&gt;Gaelyk&lt;/a&gt;, un framework web léger basé sur Groovy) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;mail.send sender: &quot;app-admin-email-AT-gmail-DOT-com&quot;,
   to: &quot;recipient-AT-somecompany-DOT-com&quot;,
   subject: &quot;Hello&quot;,
   textBody: &quot;Hello, how are you doing? -- MrG&quot;,
   attachment: [data: &quot;Chapter 1, Chapter 2&quot;.bytes, fileName: &quot;outline.txt&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Il s’agit ici d’un mini DSL, dédié à l’envoi de mails. Comment imaginer plus simple ? Lorsqu’on connait la verbosité de l’API Javamail, il n’y a pas photo…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, grâce à la flexibilité de Groovy, nous avons pu :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;rendre lisible nos workflows&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;écrire un langage domaine dédié à l’écriture de règles linguistiques. Ce langage est au coeur de notre outil interne d’extraction d’informations, et est utilisé par des linguistes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A ce propos, la force de l’utilisation de Groovy dans un tel outil est multiple :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;il permet à des non informaticiens d’écrire des règles qui sont compilées en bytecode exécuté par la JVM&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;lorsque le DSL est insuffisant, les linguistes peuvent faire appel aux développeurs, qui écrivent des ``bouts de code Groovy&apos;&apos; qui réalisent les opérations complexes&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, le possible ne se limite plus à l’expressivité du DSL. C’est un point particulièrement important à comprendre : si on avait choisi d’écrire un DSL classique, un moteur à base de règles disposant de sa propre syntaxe, nous aurions certes sans doute atteint un niveau de lisibilité supérieur à ce qu’il est possible de faire en Groovy, mais nous aurions du :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;soit écrire un interpréteur, version simple, soit un compilateur, version complexe, de règles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;développer de nouvelles versions du langage au fur et à mesure que les besoins apparaissent&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Avec Groovy, on s’affranchit de ces deux étapes, et on dispose d’un bonus non négligeable : il s’agit de code. Même si les linguistes écrivent des règles, il n’en reste pas moins qu’au milieu de ces règles, on peut faire appel à tout le langage, et donc faire toutes les opérations possibles et imaginables…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Chose amusante, nous nous rendons compte qu’avec le temps, nos linguistes montrent une curiosité grandissante envers la partie ``code&apos;&apos;, et tendent naturellement à générifier leurs règles : le langage devient structurant, et appele à une meilleur qualité !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_les_freins&quot;&gt;Les freins&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Si je suis jusqu’ici particulièrement entousiaste, il n’en reste pas moins que tout n’est pas rose dans le monde de Groovy. Je classerai les freins en deux catégories : les freins techniques d’une part et humains d’autre part. Aucun des deux n’est à négliger.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_les_freins_technique&quot;&gt;Les freins technique&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le premier frein technique que nous avons rencontré concerne les performances. Au cours du temps, les performances de Groovy s’améliorent fortement (et je vous garantit que c’est déjà extrêmement rapide), pour autant, il ne faut pas s’attendre à des miracles. En particulier, dans le cadre de notre moteur d’extraction de données, nous avions un impératif de performance extrême. L’objectif, à titre d’exemple, était d’écrire un moteur d’extraction des données d’un CV (nom, prénom, informations personnelles, expériences, entreprises, formations, …) en moins d’une seconde en moyenne par CV. Si le coeur du moteur avait été écrit en Groovy, jamais nous n’aurions atteint de telles performances. Ainsi, pour ce projet particulier, le code critique est écrit en Java, et le code ``domaine&apos;&apos;, autrement dit, ce qui correspond à la syntaxe, est écrit en Groovy. On dispose alors d’un excellent compromis : la syntaxe simplifiée Groovy avec les performances de Java.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ainsi, si Groovy permet de simplifier énormément la syntaxe, il est aussi tout à fait possible d’écrire du code très peu performant. J’ai en mémoire une première version du code de parsing du fichier XML de configuration du moteur. Ce code avait d’abord été écrit en Groovy, parce qu’il permettait grâce au &lt;em&gt;XmlSlurper&lt;/em&gt; de lire le fichier très rapidement. Seulement, la version Java était 20 fois plus rapide… L’autre exemple concerne le typage par défaut en Groovy. Assez curieusement (mais c’est un choix qui se justifie), lorsque l’on écrit ceci en Groovy :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def num = 1.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Le type associé n’est pas &lt;em&gt;float&lt;/em&gt;, mais un &lt;em&gt;BigDecimal&lt;/em&gt; (merci Guillaume pour la correction ;)). Conséquence directe, tous les benchmarks publiés sur le web concernant Groovy démontrent son extrême lenteur. Hors, il suffit de &lt;code&gt;typer&apos;&apos;, autrement dit remplacer &lt;/code&gt;def&apos;&apos; par ``int&apos;&apos; pour obtenir des performances plus que raisonnables. Pour un langage qui nous affranchit de typer, ce cas est à la limite du principe de la moindre surprise prônée par les développeurs (pour les curieux, le type par défaut est ainsi choisi parce qu’il permet d’avoir des calculs exacts, permettant ainsi d’obtenir le principe de la moindre surprise du côté des résultats).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un autre frein concerne l’utilisation de classes Groovy depuis Java. Puisque la façon naturelle de développer en Groovy est de sous-typer, on se retrouve naturellement avec des API Groovy qui ne prennent que des &lt;em&gt;Object&lt;/em&gt; en paramètre. Une pure hérérie du point de vue Java, et surtout, des API inutilisables. La plupart du temps, si votre code est destiné à être utilisé depuis une classe Java, vous devrez faire l’effort de typer correctement, quitte à perdre la lisibilité du langage.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Un autre frein technique, de moindre importance est directement lié au succès de Groovy dans l’équipe technique : on a envie d’en mettre partout. Et lorsque différents composants dépendent de différentes versions de Groovy et qu’ils doivent cohabiter, il y a risque de conflits de version. Fort heureusement, contrairement à Scala, Groovy maintient ses binaires compatibles d’une version à l’autre, ce qui permet de grandement limiter les risques.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_les_freins_humains&quot;&gt;Les freins humains&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Curieusement, les principaux freins rencontrés à l’utilisation de Groovy ne sont pas techniques. Ils sont humains. Et encore plus curieusement, ceux que j’ai rencontrés ne venaient pas de la population que j’attendais. Je m’attendais à ce que ce soient les linguistes puis les consultants qui râlent, ce furent les développeurs !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pour bien comprendre, il faut savoir que les développeurs chez Lingway ont chacun près de 10 ans d’expérience en Java. Modestement, je puis affirmer qu’ils sont bons, voire très bons. En bons développeurs, ils utilisent de bons outils : je ne peux pas comprendre qu’un développeur Java digne de ce nom utilise encore &lt;em&gt;vi&lt;/em&gt; ou &lt;em&gt;Emacs&lt;/em&gt; pour développer : la force de Java n’a jamais été le langage, mais bien les outils. En particulier, chez Lingway, nous utilisons &lt;em&gt;IntelliJ IDEA&lt;/em&gt;. Cet IDE est sans aucun doute le meilleur IDE Java disponible sur le marché. Nous l’utilisons depuis longtemps, et revenir à &lt;em&gt;Eclipse&lt;/em&gt; constituerait pour nos une punition digne du pire supplice chinois. La force de tels outils, fin de parenthèse, c’est entre autres la complétion de code. Avec un langage fortement typé tel que Java, et a fortiori avec l’utilisation des génériques, à défaut d’être compact, le code Java est compréhensible : on sait, par exemple, que telle collection contient telle liste d’objets. Le compilateur plantera si vous tentez d’enfreindre la règle, et si vous utilisez un bon IDE, sans avoir besoin de compiler, il vous indiquera les choix possibles à chaque appel de méthode, en fonction du contexte. Avec le temps, se développe ce que j’appelle la ``completion mania&apos;&apos; : l’appel du CTRL+space ou du CTRL+Q devient un trouble compulsif. Pas besoin de lire la javadoc, puisque mon IDE va gentilment me dire ce que je dois coller comme paramètre. Lorsqu’on pratique ceci intensément, on gagne un temps incroyable en développement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Dans ce contexte, le passage à Groovy apparaît comme une régression : en étant largement sous-typé (mais typé, je me bats pour qu’on comprenne que Groovy est un langage fortement typé MAIS dynamique) tant la pratique l’encourage, il est impossible, la plupart du temps, de savoir quoi passer en paramètre sans passer par la documentation de l’API. Et en matière de documentation, il y a de tout… Ici, votre IDE n’a que peu d’armes à fourbir : il est aussi perdu que vous : comment savoir quels sont les paramètre obligatoires, et quels types sont réellement attendus ? La plupart des appels au CTRL+space sont voués à l’échec, conduisant à une énorme frustration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;La tendance naturelle revient alors au galop : les développeurs Java chevronnés &lt;code&gt;Java-isent&apos;&apos; leur code, au lieu de le Groovyfier, juste pour disposer de l’intelligence de l’IDE. On perd ainsi énormément en lisibilité, contre la facilité de développement. C’est assez paradoxal, et j’essaye de me battre contre cette pratique, mais elle est difficilement contestable : je crois qu’à moins d’être extrêmement curieux et ouvert, un développeur Java expert trouvera très frustrant de &lt;/code&gt;naviguer à vue&apos;&apos;. L’impression de revenir 10 ans en arrière, avant les premiers IDE intelligents, est concrète et difficilement contestable.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;J’avoue ne pas être totalement parvenu à imprénier ``l’esprit Groovy&apos;&apos; à l’équipe de développement. Certains font de la résistance, quand d’autres font des efforts, mais c’est avant tout une question de feeling : il est très difficile de combattre les tendances naturelles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Récemment, nous sommes passés à &lt;em&gt;Grails&lt;/em&gt; pour le développement d’une application d’analyse de la e-Réputation. Le développement est encore en cours, et cette fois encore, j’ai pris le pari de bousculer l’équipe pour réussir à développer plus vite. Pour l’instant, je suis extrêmement satisfait du résultat, une productivité inégalée. Pour autant, les frustrations n’ont pas disparu. Le support de l’IDE est largement insuffisant : presque aucune complétion, pas de différenciation entre les méthodes dynamiques communes à tous les objets Groovy, et les méthodes des services, par exemple. Pas plus, non plus, d’aide sur les paramètres des méthodes &lt;em&gt;render&lt;/em&gt;, … Pour les &lt;em&gt;taglibs&lt;/em&gt;, la complétion des paramètres standard est insuffisante, et celle des taglibs custom impossible à réaliser, puisqu’aucune métadonnée n’est présente permettant à l’IDE de déduire quels paramètres sont obligatoires ou non.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_en_conclusion&quot;&gt;En conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A travers ce billet, j’ai essayé de vous dresser un portrait de l’utilisation de Groovy en mode industriel, intégré au sein de produits en production (dans notre cas, depuis 3 ans). Le bilan est largement positif, mais il ne faut pas négliger les aspects négatifs de l’intégration. En particulier, Groovy n’échappe pas à une des activités les plus complexes : la conduite du changement. Un développeur trop bien installé aura du mal à s’y mettre, et aura même tendance, parfois, à user d’une terrible mauvaise foi pour justifier des choix qui ne sont que personnels : sacrifier la lisibilité, qui fait la force de Groovy, à l’utilisation des outils, et donc au confort. Cette lutte n’est pas sans fondement, et je suis moi-même souvent en train de pester contre le manque de complétion dans mon IDE, qui impose d’avoir constamment plusieurs onglets Grails d’ouverts. Ces points noirs ne sont pas anodins, mais ne changent en rien mon avis général sur Groovy : c’est la meilleure chose qui soit arrivé à Java ces 10 dernières années. Un langage a recommander absolument, et qui je l’espère gagnera en popularité !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Downloading sources and javadocs of dependencies in Grails</title>
      <link>https://melix.github.io/blog//2010/06/28/downloading_sources_and_javadocs_for.html</link>
      <pubDate>Mon, 28 Jun 2010 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2010/06/28/downloading_sources_and_javadocs_for.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After having searched half the internet for a solution, here’s the simplest one I’ve found for downloading the sources and the javadoc of dependencies in Grails :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;grails install-plugin eclipse-scripts
grails download-sources-and-javadocs&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that you actually don’t need to use Eclipse for this to work (I don’t). Unfortunately, Jetbrains’ IntelliJ IDEA will not recognize sources and javadocs automatically, so you’ll have to attach them manually. No magic trick for that. For those interested in this feature, please &lt;a href=&quot;https://youtrack.jetbrains.net/issue/IDEA-53294&quot;&gt;vote for it&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m quite astonished this feature is not bundled with Grails. It’s much more complicated to actually deal with third party libraries without access to either the documentation or the sources…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;[edit]Jetbrains have fixed the &lt;a href=&quot;https://youtrack.jetbrains.net/issue/IDEA-53294&quot;&gt;issue&lt;/a&gt;, but only in IntelliJ IDEA X. Hope it’ll get backported to 9.0.x.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Coding a Groovy closure in pure Java</title>
      <link>https://melix.github.io/blog//2010/04/19/coding_a_groovy_closure_in.html</link>
      <pubDate>Mon, 19 Apr 2010 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2010/04/19/coding_a_groovy_closure_in.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today I just wanted to share a simple trick that’s not well documented in Groovy : in a project which mixes Java and Groovy code, I’ve faced a problem where I wanted to use a Groovy method in Java which took a &lt;em&gt;Closure&lt;/em&gt; as a parameter. Here’s how to do it. Actually, it’s quite simple :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Groovy&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;class Operation {
    def op(list, action) {
        list.each { action(it) }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class MyJavaClass {
    private Operation groovy = new Operation();

    private void shouldBeUsedAsClosure(Object o) {
        System.out.println(o);
    }

    public void demonstrateClosureUsage() {
        // creates a closure which delegates calls to this Java object
        MethodClosure cl = new MethodClosure(this, &quot;shouldBeUsedAsClosure&quot;);
        groovy.op(Arrays.asList(&quot;hello&quot;, &quot;world&quot;), cl);
    }

    public static void main(String... args) {
         MyJavaClass java = new MyJavaClass();
        java.demonstrateClosureUsage();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This example is straighforward, however, this allows you to write your custom ``closures&apos;&apos; directly in Java. This is somehow interesting whenever performance matters and that critical portions of code need to be coded in Java.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that you can have multiple methods with the same name, Groovy will automatically dispatch the call to the appropriate delegate :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class MyJavaClass {
    private Operation groovy = new Operation();

    private void shouldBeUsedAsClosure(String str) {
        System.out.println(str.toUpperCase());
    }

    private void shouldBeUsedAsClosure(int x) {
        System.out.println(x*x);
    }

    public void demonstrateClosureUsage() {
        // creates a closure which delegates calls to this Java object
        MethodClosure cl = new MethodClosure(this, &quot;shouldBeUsedAsClosure&quot;);
        groovy.op(Arrays.asList(&quot;hello&quot;, &quot;world&quot;,&quot;this&quot;,&quot;should&quot;,&quot;print&quot;,&quot;4 : &quot;,2), cl);
    }

    public static void main(String... args) {
         MyJavaClass java = new MyJavaClass();
        java.demonstrateClosureUsage();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is an elegant way to avoid multiple &lt;em&gt;instanceOf&lt;/em&gt; tests to check the type of the closure arguments. Last but not least, Groovy also provides a way to call static methods as closures, passing the class instead of an instance as the owner parameter :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;   MethodClosure cl = new MethodClosure(MyJavaClass.class, &quot;staticMethod&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Has the Java build tools war begun ?</title>
      <link>https://melix.github.io/blog//2010/04/15/has_the_java_build_tools.html</link>
      <pubDate>Thu, 15 Apr 2010 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2010/04/15/has_the_java_build_tools.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_at_the_beginning_everything_was_simple&quot;&gt;At the beginning everything was simple&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this post I will not discuss the pros and cons of each and every build tool (mainly because I only worked with Ant and Maven and know and read about the others), but rather start a debate on whether so many tools is required : I’m uncomfortable with the increasing number of build tools available for Java. At the beginning, everything was simple : Ant was here, and did its job. However, while Ant is very good at build customization, it had the cons of its pros: for each project, you had to copy parts of your ant scripts from another project, or create an Ant plugin. However, in every organization, or worse, every developer had its own way of building projects, organizing source code and so you could rapidly come with projects which used the same build tool, but in a totally different manner.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_then_came_maven&quot;&gt;Then came Maven&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m quite happy with Maven 2, which allows us to get reproducible, standardized builds with dependency management. While Maven is not perfect, it has many advantages over Ant, the most important thing to my eyes beeing that the convention based idea forces well structured and understandable code layout. It makes switching from one project to another easy because every project ``look like&apos;&apos; another. You know where to find sources, test sources, resources and so on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, Maven 2 is far from perfect, and has many problems :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;very poor documentation : there are tons of plugins, but documentation for each plugin is often insufficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;build descriptors are verbose : that’s XML. XML is verbose.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;builds are slow : each build requires parsing the XML files, checking for dependencies, downloading, … and incremental compilation is mostly broken&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;integrating libraries which do not use Maven, or worse, code compilers/generators which don’t have a Maven plugin is a pain (think of Flex, which lacked a decent plugin until very recently).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Starting from those (and other) problems, people started to create new build tools. To my knowledge, the first one was Ivy, which basically Ant plus dependency management. Great for guys who can’t stand Maven’s well structured (but conservative) build architecture but love the idea of dependency management introduced by Maven. Got to build Flex ? Ok, call the Flex compiler as an Ant task. Done.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_then_came_groovy&quot;&gt;Then came Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I love &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy&lt;/a&gt;. It’s easy to learn if you’re comfortable with Java, and it makes it very easy to write DSLs. The first thing to come was the integration of Ant into Groovy, and the creation of a Groovy DSL for Ant : Gant. It offers you the way to call Ant tasks from Groovy code easily, or, would you like it, build your project with Gant and Groovy code instead of XML files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A few days ago, the developers announced that Groovy 1.8, the next major version, would use &lt;em&gt;Gradle&lt;/em&gt; as a build tool instead of &lt;em&gt;Ant&lt;/em&gt;. What it &lt;a href=&quot;https://www.gradle.org/&quot;&gt;Gradle&lt;/a&gt; ? As far as I understand, Gradle can be thought as a Groovy DSL for both Ant and Maven 2, while it does not rely on Maven : it takes the ideas from Maven, combines them with the descriptive tasks from Ant which makes it easy to build customized builds. Why is it so easy ? Well, just because your Gradle builds is actually Groovy code…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s the idea. Ok, but I’m aware of different tools which do the same thing :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://buildr.apache.org&quot;&gt;Buildr&lt;/a&gt;, from Apache, defined as &lt;em&gt;A drop-in replacement for Maven 2.0, Buildr uses the same file layout, artifact specifications, local and remote repositories&lt;/em&gt;, but uses a dedicated language (not XML, nor Groovy).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://kundo.dev.java.net/&quot;&gt;Kundo&lt;/a&gt;, which just seems to do exactly the same thing as Gradle, but leaks a decent documentation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.codehaus.org/display/GMAVEN/Home&quot;&gt;GMaven&lt;/a&gt;, which is a Maven plugin which allows you to compile Groovy code from Maven, compiling and using code from and to Java in Groovy, and allows you to write parts of your build process in Groovy too. This is the tool I’m currently using to build Groovy code from Maven.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.wakaleo.com/blog/236-writing-your-pom-files-in-groovy-a-sneek-preview-of-maven-3s-polyglot-features&quot;&gt;Maven 3&lt;/a&gt;, yet to be released, which will allow you to abandon your XML files for a Groovy DSL, and use Groovy code in your builds. From what I read, it will likely allow us to to the same thing as Gradle and the previously mentioned tools&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This list is based on tools I’m aware of, there must be some other tools available too. But the question is here : &lt;strong&gt;do we really need so many tools ?&lt;/strong&gt;. For me, Ant is required, for its simplicity which allows building projects or libraries without taking care of the Java ecosystem. Maven is required for any larger project, or for OpenSource projects or libraries : thanks to conventional rules and dependency management, it’s quite easy to integrate any library. That makes two. For me, &lt;em&gt;Gradle&lt;/em&gt; and other tools are more likely tools that make it &lt;strong&gt;easier&lt;/strong&gt; to build complex projects than revolutionary approches : nothing was impossible to do with Ant or Maven. With Groovy support coming in Maven 3, I’m really wondering if it’s worth learning a new language at the time development teams become comfortable with Maven.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In another software development domain, it makes me think about version control : CVS, Subversion, now Git and Mercurial… And you, what do you think : has the war already begun ?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JLangdetect 0.2 released</title>
      <link>https://melix.github.io/blog//2009/09/30/jlangdetect_0_2_released.html</link>
      <pubDate>Wed, 30 Sep 2009 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2009/09/30/jlangdetect_0_2_released.html</guid>
      	<description>
	&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_jlangdetect_0_2_released&quot;&gt;JLangDetect 0.2 released !&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is a small update which includes the following features :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Ability to detect the language of a document using a subset of the languages used for training&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Logs now managed by log4j&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The ability to use a subset of the languages used for training is important if you know that a document must be written in french or english, for example, but the detector has been trained for more languages. Using a subset will ensure that the detector returns one of those languages.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_downloads&quot;&gt;Downloads&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect is licensed under &lt;a href=&quot;https://www.apache.org/licenses/LICENSE-2.0.html&quot;&gt;Apache 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Binary : &lt;a href=&quot;https://www.jroller.com/melix/resource/jlangdetect/jlangdetect-0.2.jar&quot;&gt;jlangdetect-0.2.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://www.jroller.com/melix/resource/jlangdetect/jlangdetect-0.2-sources.jar&quot;&gt;jlangdetect-0.2-sources.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Javadoc: &lt;a href=&quot;https://www.jroller.com/melix/resource/jlangdetect/jlangdetect-0.2-javadoc.jar&quot;&gt;jlangdetect-0.2-javadoc.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Europarl pre-compiled corpus: &lt;a href=&quot;https://cedric.champeau.free.fr/jlangdetect/ngrams-europarl.zip&quot;&gt;ngrams-europarl.zip&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_version_control&quot;&gt;Version Control&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Project is hosted on &lt;a href=&quot;https://code.google.com/p/jlangdetect/&quot;&gt;Google code&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>JLangdetect available at google code</title>
      <link>https://melix.github.io/blog//2009/07/16/jlangdetect_available_to_google_code.html</link>
      <pubDate>Thu, 16 Jul 2009 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2009/07/16/jlangdetect_available_to_google_code.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Several persons asked for it, so I took some time to create a google code project for JLangdetect. You’ll find it here :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://code.google.com/p/jlangdetect/&quot; class=&quot;bare&quot;&gt;https://code.google.com/p/jlangdetect/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had not much time to improve it, so feel free to contribute. My ideas for future directions include :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;remove ``irrevelant&apos;&apos; portions of texts from corpora to reduce the size of the n-gram trees&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;add ability to limit the tested text to a subset of test languages (useful if you know that your text is either in english or french, but your detector is configured with more languages)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;add pre-filters to both learning and detection algorithms in order to address problems like case (if the corpus is a large well written text but the tested string is an uppercase title, then detection will likely be wrong)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;improve detection thanks to pluggable add-ons like lexicon recognition, …&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Take a look at my posts related to &lt;a href=&quot;https://www.jroller.com/melix/tags/jlangdetect&quot;&gt;JLangdetect&lt;/a&gt; for more details.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Ubuntu Jaunty unusable for Swing debugging ?</title>
      <link>https://melix.github.io/blog//2009/04/30/ubuntu_jaunty_unusable_for_swing.html</link>
      <pubDate>Thu, 30 Apr 2009 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2009/04/30/ubuntu_jaunty_unusable_for_swing.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_ubuntu_9_04_jaunty_unusable_for_swing_gui_debugging&quot;&gt;Ubuntu 9.04 Jaunty unusable for Swing GUI debugging ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I (and Thomas Singer) am having trouble with debugging Swing GUIs under Jaunty. The problem, &lt;a href=&quot;https://www.jetbrains.net/devnet/message/5237046&quot;&gt;described in this post&lt;/a&gt; doesn’t seem to be only related to IDEA, but is rather annoying : the whole desktop freezes when the debugger reaches a breakpoint. The only way to release the lock is to switch to a console with CTRL+ALT+F1 and kill the debugged process.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It looks like some already &lt;a href=&quot;https://wiki.netbeans.org/wiki/view/FaqDebuggingAWTXWindows&quot;&gt;had the problem with Netbeans&lt;/a&gt; in previous versions of the JDK, and a workaround was available thanks to the &lt;em&gt;AllowDeactivateGrabs&lt;/em&gt; option in &lt;em&gt;xorg.conf&lt;/em&gt;. However, it seems that this &lt;a href=&quot;https://bugs.launchpad.net/ubuntu/+source/xorg-server/+bug/338489&quot;&gt;option has been removed from Xorg&lt;/a&gt;. That’s a pity as it just doesn’t leave any workaround for this bug.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If anyone has a solution, please do not hesitate to comment this post, or &lt;a href=&quot;https://www.jetbrains.net/devnet/message/5237046&quot;&gt;join the discussion&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>[Update] Adobe releases a buggy flash plugin once again</title>
      <link>https://melix.github.io/blog//2008/10/15/adobe_releases_a_buggy_flash.html</link>
      <pubDate>Wed, 15 Oct 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/10/15/adobe_releases_a_buggy_flash.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today more than ever, I’m really angry about Adobe. They have just released a brand new Flash 10 plugin with a very annoying bug which is there for months : Adobe hates Linux users, especially non-US users. Would anyone tolerate that a Windows user can’t write text in its favorite editor ? No, because if you’re not able to input text, you are not able to do anything with your computer. It’s just what’s happening with this Linux release once again : special characters (unicode) like accents, @, \{, … can’t be entered.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The bug has been reported &lt;strong&gt;&lt;a href=&quot;https://bugs.adobe.com/jira/browse/FP-40&quot;&gt;in early April this year&lt;/a&gt;&lt;/strong&gt; AND IT’S STILL NOT FIXED ! Furthermore, no one at Adobe deigns to answer. Adobe ignores 39 votes, placed 10th most voted in the bug tracker. You’ll also notice that the most voted is another Linux issue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It’s really a pity that Adobe does not wish to take Linux users seriously. It just makes impossible to release Flex based applications for customers which use Linux. More, it makes our work harder since, like me, many developers develop on this platform.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; : I had a &lt;a href=&quot;https://www.jroller.com/melix/entry/adobe_releases_a_buggy_flash#comments&quot;&gt;comment from Adobe&lt;/a&gt; this morning, saying they are working on the issue. I hope this is good news for us, and that I’ll be able to reconsider my opinion soon.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Language detection : more thoughts</title>
      <link>https://melix.github.io/blog//2008/09/25/language_detection_more_thoughts.html</link>
      <pubDate>Thu, 25 Sep 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/09/25/language_detection_more_thoughts.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Following my &lt;a href=&quot;https://www.jroller.com/melix/entry/nlp_in_java_a_language&quot;&gt;previous post&lt;/a&gt;, some people asked me if JLangDetect was sufficient by itself. The obvious answer is no. There are many reasons for that. A good language detection should combine several heuristics. JLangDetect is one. In Lingway KM, we use several techniques to improve detection. For example, there are few steps that you must ensure, in order to maximize your chances.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect does a good job because it requires a correct input :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;have the inputstream is correctly read, meaning you should ensure that character encoding is correct. Java internaly encodes string in unicode, but your reader must know the encoding &lt;strong&gt;before&lt;/strong&gt; reading the bytes. This makes it not as trivial as it first seems, and that’s why projects like JChardet exist. Read a iso-latin1 character stream as if it was unicode, and your language detection will be totally broken.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;make sure you have raw text : HTML and XML is forbidden. Language detection is optimal on plain text. Tags are very noisy, and will result in wrong language detection.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try to keep revelant parts of the input stream : if your text is issued from a web page, there are chances that you’ll get noise caused by advertisements, menus and so on. You should try to keep your detector focused on what you want to detect : the language of the text.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>NLP in Java : A language detector</title>
      <link>https://melix.github.io/blog//2008/09/21/nlp_in_java_a_language.html</link>
      <pubDate>Sun, 21 Sep 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/09/21/nlp_in_java_a_language.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;em&gt;Check out the &lt;a href=&quot;https://www.jroller.com/melix/entry/jlangdetect_0_3_released_with&quot;&gt;latest version of the project&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hi,&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Today I’m introducing a simple yet already working full Java language identifier. In natural language processing, there are tons of cases where you need to identify the language of a document first. While you’ll find most implementations in Perl, Java seems to be lacking in this domain.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_jlangdetect_a_java_language_detector&quot;&gt;JLangDetect : a Java language detector&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_introduction&quot;&gt;Introduction&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect is a pure Java implementation of a language detector. It provides a toolkit for training language recognition, and a simple implementation of a detector.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_how_to_use_it&quot;&gt;How to use it&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To identify the language of a text, just pass in a string to the sensor. It will respond a language code :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;String lang = detector.detectLang(text, false);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A detector is created this way :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;LangDetector detector = new LangDetector();
detector.register(&quot;fr&quot;, frenchTree);
detector.register(&quot;en&quot;, englishTree);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_how_it_works&quot;&gt;How it works ?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect is based on n-gram tokenization. Basically, texts are tokenized with different token sizes. For example, given the text ``cat&apos;&apos;, n-gram tokenization for 1 to 3 token sizes will produce the following tokens :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;c&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;t&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ca&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;at&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cat&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The idea is to tokenize a large set of documents in a given language and record token statistics. When you need to identify a language, then you’ll tokenize it the same way, and you’ll be able to score the input string against several token stats.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_a_gram_tree&quot;&gt;A gram-tree&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For now, JLangDetect stores token statistics in a memory-based structure called a &lt;em&gt;gram tree&lt;/em&gt;. A gram tree will record the number of times a given n-gram is found in the document library (called &lt;em&gt;corpus&lt;/em&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are ways to obtain a more compact representation, that will be likely found in future releases, but this one works like a charm. I’ve made it &lt;em&gt;Serializable&lt;/em&gt; so that storing/reading from file system pre-compiled gram trees is easy.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_testing_jlangdetect&quot;&gt;Testing JLangDetect&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_choosing_a_corpus&quot;&gt;Choosing a corpus&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For my own tests, I’ve searched a corpus which would satisfy the best conditions for the JLangDetect algorithm. It includes :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the fact that the corpus size should be rather the same for every language&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;if not, the characters used in the corpus should be rather different (for example, it’s easy to discriminate between french and russian, because they use different characters, however, if you want to differenciate french and english, you need more accurate n-gram statistics).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;A ``parallel corpus&apos;&apos; is a good candidate for that : it’s a corpus for which the text is simply the same, translated in different languages. I’ve made my test using the &lt;a href=&quot;https://www.statmt.org/europarl/&quot;&gt;European Parliament Proceedings Parallel Corpus&lt;/a&gt;. It covers the proceedings of the european parliament from 1996 to 2006, which is up to 40 million words per language.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Translations exists for the following languages :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;danish (da)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;german (de)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;greek (el)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;english (en)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;spanish (es)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;finnish (fi)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;french (fr)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;italian (it)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dutch (nl)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;portuguese (pt)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;swedish (sv)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You’ll find a precompiled version of this corpus at the bottom of this page, if you wish to use it with JLangDetect. On my computer with a quad-core processor (Q9450), it took less than 10 minutes to process the whole corpus, I’ve optimized the importer for multi-core systems.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_accuracy&quot;&gt;Accuracy&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect, with the previous corpus, does really well with both short and long texts. However, it will do better with longer texts (if anyone can tell me in which language is written the word ``chocolate&apos;&apos;…).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s a simple output of JLangDetect. OK means language has been detected properly. Error means not.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;langof(&quot;un texte en français&quot;) = fr : OK
langof(&quot;a text in english&quot;) = en : OK
langof(&quot;un texto en español&quot;) = es : OK
langof(&quot;un texte un peu plus long en français&quot;) = fr : OK
langof(&quot;a text a little longer in english&quot;) = en : OK
langof(&quot;a little longer text in english&quot;) = en : OK
langof(&quot;un texto un poco mas longo en español&quot;) = es : OK
langof(&quot;J&apos;aime les bisounours !&quot;) = fr : OK
langof(&quot;Bienvenue à Montmartre !&quot;) = fr : OK
langof(&quot;Welcome to London !&quot;) = en : OK
langof(&quot;un piccolo testo in italiano&quot;) = it : OK
langof(&quot;een kleine Nederlandse tekst&quot;) = nl : OK
langof(&quot;Matching sur des lexiques&quot;) = fr : OK
langof(&quot;Matching on lexicons&quot;) = en : OK
langof(&quot;Une première optimisation consiste à ne tester que les sous-chaînes de taille compatibles avec le lexique.&quot;) = fr : OK
langof(&quot;A otimização é a primeira prova de que não sub-canais compatível com o tamanho do léxico.&quot;) = pt : OK
langof(&quot;Ensimmäinen optimointi ei pidä testata, että osa-kanavien kanssa koko sanakirja.&quot;) = fi : OK
langof(&quot;chocolate&quot;) = es : Error
langof(&quot;some chocolate&quot;) = it : Error
langof(&quot;eating some chocolate&quot;) = en : OK&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; Chocolate is an error as I tagged it as english in my test case, but one could expect it to be spanish. It’s here to demonstrate the limits of the system for very short texts. As for ``longo&apos;&apos;, long time I’ve not written spanish. Bisounours is a french joke ;) Feel free to comment ;)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_downloads&quot;&gt;Downloads&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;JLangDetect is licensed under &lt;a href=&quot;https://www.apache.org/licenses/LICENSE-2.0.html&quot;&gt;Apache 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Binary : &lt;a href=&quot;https://cedric.champeau.free.fr/jlangdetect/jlangdetect-0.1.jar&quot;&gt;jlangdetect-0.1.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://cedric.champeau.free.fr/jlangdetect/jlangdetect-0.1-sources.jar&quot;&gt;jlangdetect-0.1-sources.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Javadoc: &lt;a href=&quot;https://cedric.champeau.free.fr/jlangdetect/jlangdetect-0.1-javadoc.jar&quot;&gt;jlangdetect-0.1-javadoc.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Europarl pre-compiled corpus: &lt;a href=&quot;https://cedric.champeau.free.fr/jlangdetect/ngrams-europarl.zip&quot;&gt;ngrams-europarl.zip&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Java 7 idea : change default file encoding</title>
      <link>https://melix.github.io/blog//2008/09/16/java_7_idea_change_default.html</link>
      <pubDate>Tue, 16 Sep 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/09/16/java_7_idea_change_default.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Apart from closures I eventually doubt will be integrated into Java 7, there’s something I’d really like to see, althought it introduces a (small yet easily fixable) change : I think the default &lt;strong&gt;source file encoding&lt;/strong&gt; should be the same for all platforms. Thumbs up for UTF-8, since it is able to represent most of characters for every language (for exotic characters, you still may use \uxxxx notation).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I still can’t understand (but there must be valid reasons apart from people creating files with notepad) why the default source file encoding is not the same on every platform. The biggest problem is when using multiple development environments on the same project : people using Windows create source files using &lt;em&gt;cp1252&lt;/em&gt; while people like me, programming under Linux, are using &lt;em&gt;utf-8&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem occurs when people introduce special characters (very common in french, for example in string constants or comments) in source code : you won’t be able to build under another platform unless you specify the source file encoding flag, which is rather annoying.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem can be obviously fixed with your favorite editor (IntelliJ IDEA allows choosing the default file encoding), but I’d really like it to be fixed in the compiler, so that the builds are consistent accross multiple platforms (plus, if you use continuous integration, there are chances that your build server is not using the encoding you expect).&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>The strange Hibernate version numbers</title>
      <link>https://melix.github.io/blog//2008/08/21/the_strange_hibernate_version_numbers.html</link>
      <pubDate>Thu, 21 Aug 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/08/21/the_strange_hibernate_version_numbers.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I am fascinated with Hibernate version numbers. Have you noticed how uncommon they are ? In the open source community, almost every project follows the same rules :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;project-MAJOR.minor.bugfix&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;commons-io-1.2.3&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;spring-core-2.0.0&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If necessary, you may append release specific modifiers :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;alpha version : -alpha1, -alpha2, …&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;beta version : -beta1, -beta2, …&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;release candidate : -rc1, …&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Hibernate does not follow those conventions. You may find :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;hibernate-3.2.0.cr1 : why not hibernate-3.2.0-rc1 ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hibernate-3.3.0.ga : why not hibernate-3.3.0 ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hibernate-3.3.0.SP1 : why not hibernate-3.3.1 ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hibernate-search-3.1.0.Beta1 : why not hibernate-search-3.1.0-beta1 ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you are used to Maven, then you must have been annoyed with it, as the &lt;a href=&quot;https://repo1.maven.org/maven2/org/hibernate/hibernate/&quot;&gt;resulting artifacts never follow the same conventions&lt;/a&gt; (with or without dash, uppercase or not, …).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Pretty frustrating. As a widely used library, I would expect Hibernate to follow the most common versioning schemes…&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>XPointer support in JDK is incomplete</title>
      <link>https://melix.github.io/blog//2008/07/16/xpointer_support_in_jdk_is.html</link>
      <pubDate>Wed, 16 Jul 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/07/16/xpointer_support_in_jdk_is.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;There are some days when you want to kill people who don’t document their code, and some where you just want to kill those who silently ignore specifications. Today, I’ve spent hours digging into the source code of the Sun JDK (1.5) in order to find out why one of my XML inclusions did not work. Worse, there wasn’t a single warning, nor a single error in the console…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_story&quot;&gt;The story&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m using &lt;a href=&quot;https://www.w3.org/TR/xinclude/&quot;&gt;XInclude&lt;/a&gt; to split long XML files into smaller parts. Basically, it allows you to write things like this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;--

You may activate this feature using the following lines of configuration :

code,prettyprint&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;[source]&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;--

(note the *xpointer=``xpointer(//macros/*)&apos;&apos;* syntax).

Well, if you came to this page thinking you’d find a solution to the fact that this does not work, I can’t help you. It doesn’t. While the documentation says that _XInclude_ support is implemented in the JDK, the truth is that it is incomplete. The JDK just supports the https://www.w3.org/TR/xinclude/#XPElement[element scheme] but not the https://www.w3.org/TR/xinclude/#XPointer[xpointer scheme]. Well, the specification of XInclude says that the implementation of the second one is optional, but the main problem with the JDK is that is never throws an _UnsupportedOperationException_. Worse, it silently parses your includes, and never throws any error (hence, the xi:fallback element is ignored).

[[]]
XPointer scheme support ?&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If you know about a Java library which supports the &lt;em&gt;xpointer scheme&lt;/em&gt;, please let me know, I haven’t found any yet.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>&lt;strong&gt;gasp&lt;/strong&gt; Dell Optiplex 740 bios upgrade failure</title>
      <link>https://melix.github.io/blog//2008/06/06/gasp_dell_optiplex_740_bios.html</link>
      <pubDate>Fri, 6 Jun 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/06/06/gasp_dell_optiplex_740_bios.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This morning, I wanted to upgrade my BIOS to check out if the changes made to the nforce chipset support were to improve disk performance on my Ubuntu box… First, the bad thing is that you need to boot Windows to be able to upgrade. Fortunately, I had a (very) small Windows XP partition for that kind of things. So I launched the upgrade and &lt;strong&gt;gasp&lt;/strong&gt;, it kept spawning messages like this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;FAILURE !! FAILURE !!
Click ok to try to reflash BIOS&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, BIOS was cleared, no new BIOS installed… After fighting up several minutes, I managed to get the upgrade complete. For those who would experience the same mess, here’s the trick : increase the priority of the BIOS upgrade process to ``higher than normal&apos;&apos;. Back to Ubuntu ;)&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Simplifiying java.util.concurrent with Groovy</title>
      <link>https://melix.github.io/blog//2008/04/02/simplifiying_java_util_concurrent_with.html</link>
      <pubDate>Wed, 2 Apr 2008 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2008/04/02/simplifiying_java_util_concurrent_with.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ever wondered how to simplify &lt;em&gt;java.util.concurrent&lt;/em&gt; usage with Groovy ? Here’s a simple example of what can be easily done using closures. The following code executes several closures in parallel and waits upon completion before resuming the script.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def doInParallel(Closure... closures) {
 def service = java.util.concurrent.Executors.newFixedThreadPool(closures.length)
 def latch = new java.util.concurrent.CountDownLatch(closures.length)
 closures.each { cl -&amp;gt; service.execute({
  try {
   cl.call()
  } catch (e) {
   throw e
  } finally {
   latch.countDown()
  }
 })}
 latch.await()
 service.shutdown()
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s how to use it :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;doInParallel(
   { println 1+1 },
   { callVeryLongProcess() },
   { throw Exception() } // demonstrates the correct handling of exceptions
)

println &quot;This line of code will only appear after every closure in doInParallel is completed&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Fun, isn’t it ?&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Moving Lucene a step forward</title>
      <link>https://melix.github.io/blog//2008/03/20/why_lucene_isn_t_that.html</link>
      <pubDate>Thu, 20 Mar 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/03/20/why_lucene_isn_t_that.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_introduction&quot;&gt;Introduction&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At &lt;a href=&quot;https://www.lingway.com&quot;&gt;Lingway&lt;/a&gt;, we’ve been using Lucene for a few years now. For those who are new to Lucene, here’s its bottomline : &lt;em&gt;Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java.&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Before criticizing, I must admit that Lucene &lt;strong&gt;is&lt;/strong&gt; a very good high-performance full text search engine. For years, &lt;a href=&quot;https://lucene.apache.org&quot;&gt;Lucene&lt;/a&gt; has been considered as a first class citizen when looking for an embeddable search engine written in Java. Its reputation has grown fast, and it is still now the best open source Java search engine available. There’s nothing to say about that : Doug Cutting has done a great job. However, it’s development has been going very slow those late months, and I think Lucene will most likely not keep in touch with today’s document processing needs. Don’t mess up : I am no search engine developer, I am a developer which leverages search engines in order to provide high relevance information retrieval technologies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This post is about why Lucene may not be the best choice for future developments if nothing is done, and why the situation may not be close to change. In our situation, we push Lucene to its limits, although we make it work quite good. It’s a reason why we made some suggestions and submitted a patch to Lucene (which does not cover everything listed here) : &lt;a href=&quot;https://www.lingway.com&quot;&gt;Lingway&lt;/a&gt; uses semantics to generate complex queries where proximity matters. For example, if you are looking for documents on &lt;em&gt;conflicts in middle east&lt;/em&gt;, you’ll probably also want to find documents talking about &lt;em&gt;war in Iraq&lt;/em&gt;. In that case, &lt;em&gt;war&lt;/em&gt; and &lt;em&gt;Iraq&lt;/em&gt; are called expansions of &lt;em&gt;conflict&lt;/em&gt; and &lt;em&gt;middle east&lt;/em&gt; respectively. We provide a technology which analyzes your query in order to deduce the most relevant expansions, and generate queries for them. Yet, in order to get &lt;em&gt;relevant&lt;/em&gt; results, this is insufficient : Google-like ranking or term frequency scoring like implemented in Lucene do not suit semantic scoring needs. For example, a document which contains both &lt;em&gt;middle&lt;/em&gt; and &lt;em&gt;east&lt;/em&gt; terms but separated by more than 1 word are most likely not what you want to find. Moreover, we should attribute lower scores on expansions than on the regular words. For example, we’ll give a better score to &lt;em&gt;conflict in middle east&lt;/em&gt; phrase than in &lt;em&gt;war in Iraq&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;At Lingway, we think this kind of document retrieval technology is the future of search engines. Google is good at finding documents, but what we want is to find the most relevant ones. However, most (if not all) of current search engines have not been thought to perform such complex queries… Lucene is used by wikipedia, and you’ll notice that if you try to find more than a single word, most results are irrevelant…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s a capture of the upcoming Lingway KM 3.7 interface, which demonstrates the requirements. Here, we write a query in french, which is used to find documents in english talking about the same subject. Note that this is more than plain translation, we call it cross language mode :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/lkm/lkm37.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note the matches in green : &lt;em&gt;chanteur&lt;/em&gt; becomes &lt;em&gt;singer&lt;/em&gt;, but we also find matches about &lt;em&gt;singing&lt;/em&gt;. Same for &lt;em&gt;pop&lt;/em&gt; which expands to &lt;em&gt;blues&lt;/em&gt;… Now for the technical part:&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_6_ways_of_improving_lucene&quot;&gt;6 ways of improving Lucene&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\6. &lt;strong&gt;No built-in support for clustering&lt;/strong&gt;. If you want to create clusters, either write your own implementation of a &lt;em&gt;Directory&lt;/em&gt;, or use &lt;a href=&quot;https://lucene.apache.org/solr/&quot;&gt;Solr&lt;/a&gt;, or &lt;a href=&quot;https://lucene.apache.org/nutch/&quot;&gt;Nutch&lt;/a&gt;+https://hadoop.apache.org/[Hadoop]. Both Solr and Nutch leverage Lucene, but are not straight replacements. Lucene is embeddable, while you must leverage on Solr or Nutch. Well, I think it is not very surprising that Hadoop idea emerged from the Lucene team : Lucene doesn’t scale out. It’s internals makes it (very) fast for most common situations, but for large document sets, you &lt;strong&gt;have to&lt;/strong&gt; scale out, and as Lucene does not implement clustering at the core level, you must switch from Lucene to another search engine layer, which is not straightforward. The problem with switching to Solr or Nutch is that you carry things you probably won’t need : integrated crawling for Nutch and indexing server for Solr.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\5. &lt;strong&gt;Span queries are slow&lt;/strong&gt;. This may be interpreted as a problem specific to Lingway where we make intensive use of span queries (NEAR operator : ``red NEAR car&apos;&apos;), but the Lucene index structure has been updated to add this feature, which was not thought at first. The underlying implementation leads to complex algorithms that are very slow, especially when some term is repeated many times in a single large document. That’s why I tend to say that Lucene is a &lt;em&gt;high-performance text search engine&lt;/em&gt; &lt;strong&gt;only if you use basic boolean queries&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\4. &lt;strong&gt;Scoring is not really pluggable&lt;/strong&gt;. Lucene has its own implementation of a scoring algorithm, where terms may be boosted, and makes use of a &lt;em&gt;Similarity&lt;/em&gt; class, but soon shows limitations when you want to perform complex scoring, for example based on actual matches and meta data about the query. If you want to do so, you’ll have to extend the Lucene query classes. The facts is that Lucene has been thought in terms of tf/idf like scoring algorithms, while in our situation, for linguistic based scoring, the structure of Lucene scoring facilities don’t fit. We’ve been obliged to override every Lucene query class in order to add support for our custom scoring. And that was a problem :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\3. &lt;strong&gt;Lucene is not well designed&lt;/strong&gt;. As a software architect, I would tend to make this reason 1. Lucene has a very poor OO design. Basically, you have packages, classes, but almost no design pattern usage. I always makes me think about an application written by C(++) developers who discover Java and carry bad practices among them. This is a serious point : whenever you have to customize Lucene to suit your needs (and you will have to do so), you’ll have to face the problem. Here are some examples :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Almost no use of interfaces. Query classes (for example &lt;em&gt;BooleanQuery&lt;/em&gt;, &lt;em&gt;SpanQuery&lt;/em&gt;, &lt;em&gt;TermQuery&lt;/em&gt;…) are all subclasses of an abstract class. If you want to add a feature to those classes, you’ll basically want to write an interface which describes the contract for your extension, but as the abstract Query class does not implement an interface, you’ll have to constantly cast your custom query objects to a &lt;em&gt;Query&lt;/em&gt; in order to be able to use your objects in native Lucene calls. Tons of examples like this (HitCollector, …). This is also a problem when you wan’t to use AOP and auto-proxying.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Unnatural iterator implementations. No &lt;em&gt;hasNext()&lt;/em&gt; method, &lt;em&gt;next()&lt;/em&gt; returns a boolean and refreshes the object context. This is a pain when you want to keep track of iterated elements. I assume this have been done intentionally to reduce memory footprint but it makes once again algorithms both unclear and complex.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\2. &lt;strong&gt;A closed API which makes extending Lucene a pain&lt;/strong&gt;. In Lucene world, it is called a feature. The policy is to open classes when some user needs to gain access to some feature. This leads to an API where most classes are package protected, which means you won’t ever be able to extend it (unless you create your class in the same package, which is quite dirty for custom code) or you’ll have to copy and rewrite the code. Moreover, and it is quite related to the previous point, there’s a serious lack of OO design here too : some classes which should have been inner are not, and anonymous classes are used for complex operations where you would typically need to override their behaviour. The reason invoked for closing the API is that the code has to be cleaned up and made stable before releasing it publicly. While the idea is honourable, once again it is a pain because if you have some code that does not fit in the mainstream Lucene idea, you’ll have to constantly backport Lucene improvements to your version until your patch is accepted. However, as the developers want to limit API changes as long as possible, there’s little chance that your patch will ever be commited. Add some &lt;em&gt;final&lt;/em&gt; modifiers on either classes or methods and you’ll face the problem. I don’t think the Spring framework would have come so popular if the code had been so locked…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;\1. &lt;strong&gt;Lucene search algorithms are not adapted to grid computing&lt;/strong&gt;. Lucene has been written when hardware did not have memory that much and multicore processors didn’t exist. Therefore, the index structure has been thought and implemented in order to perform fast linear searches with a very little memory footprint. I’ve personally spent lots of hours trying to rewrite span query algorithms so that I could make use of a multithreaded context (for dual/quad core cpus), but the iterator-based directory reading algorithms make it hardly impossible to do so. In some rare cases you’ll be able to optimize things and iterate the index in parallel, but in most situations it will be impossible. In our case, when we have a very complex query with 50+ embedded span queries, the CPU is almost not used while the system is constantly calling I/Os, even using a RAMDirectory.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_any_alternative&quot;&gt;Any alternative ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think the last point is the more problematic : Lucene reaches its limits when it goes to searching large datasets (with many operators or not) on modern hardware. That’s why I’ve been looking for an alternative to Lucene. After reading blog entries and &lt;a href=&quot;https://www.nabble.com/An-alternative-to-Lucene-to8842520.html&quot;&gt;a discussion about Wikia&lt;/a&gt;, I found that there were not so many alternatives. However, I finally came to a very promising solution : &lt;a href=&quot;https://mg4j.dsi.unimi.it/&quot;&gt;MG4J&lt;/a&gt;. It has a very good object design, excellent performance on search (indexing is slower than Lucene), a small memory footprint, is up to 10x faster than Lucene on my span query benchmarks, and is nativelly designed for clustering. It also has built-in support for payloads, while in Lucene it is a very recent addition which is still experimental. However, MG4J still misses some features such as easy incremental indexation (indices ARE clusters, but there’s no idea on performance issues), document removal and an easier to use indexing process. What made me happy is that I was able to reproduce the customizations I made on Lucene in a few hours where it took me days on Lucene.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I think there’s room for a new open source search engine which is not thought in terms of a single computer indexing a collection of documents with limited memory, but in terms of transparent distributed indexation and searching in order to provide fast answers on large datasets (think of &lt;a href=&quot;https://www.terracotta.org&quot;&gt;Terracotta&lt;/a&gt; or &lt;a href=&quot;https://www.gridgain.com&quot;&gt;GridGain&lt;/a&gt; as repartition frameworks) : you should not have to leverage an application to gain access to clustering features. Lucene has an excellent implementation of the first category of search engines, but I think this is not adapted to what we require now : beeing able to find the best answer to a question in a reasonable amount of time. tf/idf based search algorithms and Google rank are not the future of search engines. Finding the most relevant answers implies complex queries involving metadata on documents and semantics, which is basically what &lt;a href=&quot;https://www.lingway.com&quot;&gt;Lingway&lt;/a&gt; does (with Lucene and other backing search engines), but it requires more power and an underlying technology which supports modern hardware.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_a_good_reason_to_choose_lucene&quot;&gt;A good reason to choose Lucene&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Whatever the reproaches I have to make about Lucene, it is still the best java open source solution available for what we are doing, and it performs quite good ;-)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Tip: Find try/catch performance bottlenecks with structural search in IntelliJ IDEA</title>
      <link>https://melix.github.io/blog//2008/02/29/tip_find_try_catch_performance.html</link>
      <pubDate>Fri, 29 Feb 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/02/29/tip_find_try_catch_performance.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Advanced Java programmers are aware that &lt;em&gt;try/catch&lt;/em&gt; statements cost many CPU cycles, so it is generally a bad idea to catch exceptions in loop statements. Moreover, even with profilers, it may be hard to find out that a &lt;em&gt;try/catch&lt;/em&gt; statement is responsible for a performance bottleneck : you have to take a look at your code, and figure out whether it should be optimized or not. In many cases, you should definitely avoid using &lt;em&gt;try/catch&lt;/em&gt; statements in loops.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Fortunately, IntelliJ IDEA has this powerful structural search feature. Let’s explain how to use it in order to find those possible bottlenecks. Structural search is powerful as it allows you to describe ``patterns&apos;&apos; of code to match. No matter the indentation, no matter the statements, you’ll just lookup for &lt;strong&gt;structural matches&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In our case, you need to look for something that ``looks like&apos;&apos; this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;for () {
  try {
  } catch () {
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The corresponding structural search pattern will be :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;for ($decl$;$condition$;$increment$) {
 $beforeStatements$;
 try {
  $TryStatement$;
 } catch ($exceptionType$ $ex$) {
  $CatchStatement$;
 }
 $afterStatements$;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To use this, either click on the ``search structurally&apos;&apos; item in the search menu, or press &lt;em&gt;Ctrl+Shift+S&lt;/em&gt; and enter the pattern :&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;span class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.jroller.com/melix/resource/idea/structwindow.png&quot; alt=&quot;image&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;+
+
Then you need to tweak the variables in order to specify the cardinalities. Click on ``Edit variables&apos;&apos;, and update :&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;beforeStatements : minimum count 0, maximum count unlimited&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;afterStatements : minimum count 0, maximum count unlimited&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tryStatement : minimum count 1, maximum count unlimited&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;catchStatement : minimum count 0, maximum count unlimited&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The other variables may stay as defaults (min 1, max 1).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now click on ``Find&apos;&apos; and you’ll probably find some of those nasty constructs. The previous patterns works for classical for loops, you need to tune it to work for &lt;em&gt;Java 5 for each constructs&lt;/em&gt;, and don’t forget &lt;em&gt;while&lt;/em&gt; loops too.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Java BGGA closures proposal and the Groovy syntax</title>
      <link>https://melix.github.io/blog//2008/02/29/java_bgga_closures_proposal_and.html</link>
      <pubDate>Fri, 29 Feb 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/02/29/java_bgga_closures_proposal_and.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;While there’s still no decision made on the integration of closure to the Java language (AFAIK), I think the &lt;a href=&quot;https://www.javac.info/&quot;&gt;BGGA proposal&lt;/a&gt; is the most promising candidate. I’m quite confident it will eventually be integrated to the language.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, I was wondering about the syntax of the proposal, mainly because more and more programmers are using closures in Groovy. Basically, you’ll write a closure in Groovy like this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;{ x,y -&amp;gt; x+y }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the BGGA proposal, the syntax is more verbose because Java is strongly typed :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;{int x, int y =&amp;gt; x + y}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Everything would be fine, but I was wondering about the &lt;em&gt;&amp;#8658;&lt;/em&gt; separator, which &lt;em&gt;can&lt;/em&gt; be confusing :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;{int x, int y =&amp;gt; x &amp;gt;= y }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;IMHO, it would be better if the proposal followed the syntax that’s getting known by more and more people, that is to say the Groovy one : replacing &lt;em&gt;&amp;#8658;&lt;/em&gt; with &lt;em&gt;&amp;#8594;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What do you think ?&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Groovy, functional programming and the curry method</title>
      <link>https://melix.github.io/blog//2008/02/15/groovy_functional_programming_and_the.html</link>
      <pubDate>Fri, 15 Feb 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/02/15/groovy_functional_programming_and_the.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m sure you have heard of functional programming, at least when you were sill a student (if you are, then you’re probably digging into it). The &lt;a href=&quot;https://groovy.codehaus.org&quot;&gt;Groovy language&lt;/a&gt;, built on top of Java, provides means of dealing with functional programming. Moreover, it offers a &lt;em&gt;curry&lt;/em&gt; method which allows powerful recursion mechanisms.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;For example, in maths, you’ll want to define the sum function of a list as the sum of the first element and the (recursive) sum of the rest of the list. Going further, you’ll want to define a meta function which defines the behaviour of the sum method :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;f(x1, x2, ...) = f(x1, f(x2, ...))&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s currying. Here’s a basic example which demonstrates this feature in Groovy. First, let’s define a reduce closure which takes as the first argument the function to be applied on the list of arguments :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;def reduce
reduce = { fn, params -&amp;gt;
    if (params.size()==1) return params[0]
 fn(params[0], reduce(fn,params[1..

Note that for the reduce function to be known inside the closure, you have to define it before (click here for details).

Then we may define the sum() function as this :

def sum = reduce.curry({ x,y -&amp;gt; x+y })&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The sum method is a closure passed as a parameter to the curry method. Technically, it is equivalent to write a function where you replace the first parameter of the reduce closure with the sum closure. Now let’s see the result :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;println sum((1..10))

--&amp;gt; 55&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;More interesting, as the parameter types are not specified, you may also use our sum function as a string or list concatenation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;println sum((&quot;a&quot;..&quot;z&quot;))

--&amp;gt; abcdefghijklmnopqrstuvwxyz

println sum([(1..10),(11..20)])

--&amp;gt; [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I &lt;strong&gt;love&lt;/strong&gt; Groovy ;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Addendum: You should also use this with caution, as it costs much in invocation time, and you should not use it for so simple functions (summing is a very bad example as the cost in time of the sum operation is much less that the method invocation cost). Furthermore, don’t forget that it is &lt;strong&gt;recursions&lt;/strong&gt;, so too many parameters will drive you too a stack overflow error ;-)&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Apache CXF + Maven + Javamail + Log4J (update)</title>
      <link>https://melix.github.io/blog//2008/02/14/apache_cxf_maven_javamail_awful.html</link>
      <pubDate>Thu, 14 Feb 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/02/14/apache_cxf_maven_javamail_awful.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I had much trouble trying to figure out why a project we moved to Apache CXF (for managing web services) suddenly started to send malformed emails. Basically, we use Commons email for sending emails to the administrator whenever a monitored service goes wrong.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Everything went good until we moved our web service layer to the powerful &lt;a href=&quot;https://incubator.apache.org/cxf&quot;&gt;Apache CXF&lt;/a&gt;. Instead of sending a well formed e-mail, the server suddenly started sending emails without subject nor correct sender. As we use Maven for building our project, and CXF makes use of Apache Geronimo Javamail/activation implementations, I immediatly suspected a buggy implementation of javamail.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Instead of sending, in the &lt;em&gt;DATA&lt;/em&gt; section of the email the following :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;DATA
From: &quot;I am the sender&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Geronimo javamail implementation only sends what was actually set as the mail content :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;DATA
the content of my mail&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I don’t know if it is a feature or a bug, but it really sucks (update : it’s neither feature nor bug, it’s a classpath messup, see the latest paragraph). To get rid of this mess, we had to exclude the geronimo dependencies from both &lt;em&gt;cxf-rt-core&lt;/em&gt; and &lt;em&gt;cxf-rt-databinding-jaxb&lt;/em&gt; modules. And, if like us you have a dependency on another module using CXF too, don’t forget to exclude from the parent module too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Basically, you shoud write something like this in your &lt;em&gt;pom.xml&lt;/em&gt; file :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;   org.apache.cxf
   cxf-rt-core
   ${cxf.version}


     org.apache.geronimo.specs
     geronimo-javamail_1.4_spec


     org.apache.geronimo.specs
     geronimo-activation_1.1_spec




   org.apache.cxf
   cxf-rt-frontend-jaxws
   ${cxf.version}


   org.apache.cxf
   cxf-rt-databinding-jaxb
   ${cxf.version}


     org.apache.geronimo.specs
     geronimo-javamail_1.4_spec


     org.apache.geronimo.specs
     geronimo-activation_1.1_spec&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then, add the Sun javamail/activation implementations instead :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;   javax.mail
   mail
   1.4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To the CXF team : &lt;strong&gt;please make those dependencies optional&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To the Maven team : &lt;strong&gt;please add the global exclude feature so that we won’t have to specify excludes on each dependency !&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; After filing a bug report on Geronimo, I’ve made further investigations. The problem is more complex than I first thought : if there were only the Geronimo dependencies, I would not have had the same error. Instead, I would have got a message telling me that it could not find the ``SMTP transport&apos;&apos;. I figured out that the problem was our log4j dependency, which depends on javax.mail. The Geronimo Spec mail API does not implement the SMTP transport : it is implemented in a separated artifact. So the SMTP transport that was used in my case what the one in the Javamail transitive dependency from log4j. The problem that seems to arise is that Geronimo is not compatible with the transport layer from Javamail : if you just order the classpath differently, all goes fine. It all depends on the library which is first loaded…&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Alternative to delegate pattern with cglib</title>
      <link>https://melix.github.io/blog//2008/02/09/alternative_to_delegate_pattern_with.html</link>
      <pubDate>Sat, 9 Feb 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/02/09/alternative_to_delegate_pattern_with.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This week I had some third party class I needed to override, but as in many cases, I had to use the delegate design pattern in order to be able to expand the class without modifying the 3rd party library.&lt;br&gt;
 &lt;br&gt;
 However, I came to a problem when the base class used the visitor pattern. The following snippet explains it all:&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class MyBaseClass implements AnInterface {

...

public void accept(Visitor visitor) {
   visitor.visit(this);
}

...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The problem is that if you delegate the doSomething() method, the object which will be passed to the visitor will be the delegate, not your implementation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class DelegatingClass implements AnInterface,AnotherInterface {
...
public void visit(Visitor visitor) {
   delegate.visit(visitor); // ok, assume you can&apos;t do visitor.visit(this), that would be too easy. Imagine the delegate does more stuff or imagine another method like doSomething() { something.call(this); }
}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This leads to situations where the visited object is not the one you’d like to, and it breaks your algorithms where you assume the visited object is your implementation (which adds several features). Futhermore, there are situations when you can’t even delegate. For examples, when extending a class with final methods, or when you try to expand a class which is package protected (there are tons of examples like this in Apache Lucene). I’ve come to a solution using the &lt;em&gt;cglib&lt;/em&gt; library. The idea is to create a proxy and dynamically extend the base class with your features. I’ve written a simple utility class which does it all :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package com.lingway.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * This utility class generates cglib proxies which delegates missing methods to instanciated
 * objects.
 * User: Cedric
 * Date: 9 févr. 2008
 * Time: 08:35:20
 */
public class AdvancedEnhancer {
    /**
     * Creates a new instance of a delegating object.
     * @param aSuperClass super class of the generated object.
     * @param someInterfaces interfaces generated object will implement.
     * @param delegates delegates which implements the &quot;missing&quot; methods.
     * @return Object&amp;lt;/&amp;gt; delegating object
     */
    public static Object enhanceWithInterfaces(
            Class aSuperClass,
            Class[] someInterfaces,
            Object[] delegates) {

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(aSuperClass);
        enhancer.setInterfaces(someInterfaces);
        enhancer.setCallback(new InterfaceMethodInterceptor(delegates));
        return enhancer.create();
    }

    /**
     * A convenient creator which assumes a single interface to be implemented
     * by a list of delegates. This allows removing explicit class casting.
     * @param aSuperClass super class of the generated object.
     * @param aTargetInterface target interface
     * @param delegates delegates which implements the &quot;missing&quot; methods.
     * @return T&amp;lt;/&amp;gt; delegating object implementing the T interface
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    public static&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And here’s an example of how it works. Pretty easy !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package com.lingway.cglib;

/**
 * A proof of concept of the &quot;cglib delegate pattern&quot;
 * User: Cedric
 * Date: 9 févr. 2008
 * Time: 14:06:56
 */
public class ProofOfConcept {
    public interface ISelf {
        ISelf self(); // basically, returns &quot;this&quot;, which is just for the POC :)
    }

    public interface IEcho {
        void echo();
    }

    public interface IMixin extends ISelf,IEcho {}

    public static class Self implements ISelf {
        public ISelf self() {
            return this;
        }
    }

    public static class Echo implements IEcho {
        public void echo() {
            System.out.println(&quot;echo !&quot;);
        }
    }

    public static void main(String[] args) {
        IEcho echo = new Echo(); // these are the &quot;additional features&quot;
        IMixin mixin = AdvancedEnhancer.enhanceWithTargetInterface(Self.class, IMixin.class, echo);
        System.out.println(&quot;mixin.self (shows this is the proxy) = &quot; + mixin.self());
        mixin.echo();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In the previous example, I ``enhance&apos;&apos; the Self class with the features of the Echo class. This is really easy, and perfectly solves our problem. Note that technically, the delegate and the delegator are switched.&lt;br&gt;
 &lt;br&gt;
 Enjoy !&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>The facts about annotations inheritance</title>
      <link>https://melix.github.io/blog//2008/01/18/the_facts_about_annotations_inheritance.html</link>
      <pubDate>Fri, 18 Jan 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/01/18/the_facts_about_annotations_inheritance.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Following my post about &lt;a href=&quot;https://www.jroller.com/melix/entry/the_truth_about_annotations_inheritance&quot;&gt;the behaviour of annotations in an inheritance model&lt;/a&gt;, &lt;a href=&quot;https://www.jroller.com/melix/entry/the_truth_about_annotations_inheritance#comments&quot;&gt;Mike Kaufman made a very interesting comment&lt;/a&gt;. The &lt;strong&gt;truth&lt;/strong&gt;, as I said, is that annotations are &lt;strong&gt;technically&lt;/strong&gt; inherited only if the annotation definition itself is annotated with &lt;em&gt;@Inherited&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I must admit that while this is technically true, the facts are not so simple. Let me explain why I came to this test case. I had written a web service using the Metro (JAX-WS RI) project. With project Metro, web services are defined with annotations. For example, you would write :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@WebService(serviceName=&quot;myService&quot;)
public class MyService {
    @WebMethod
    public int sum(int x, int y) { return x+y; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This is a very convenient (and easy) way of building web services. But services should always be defined through interfaces. Therefore, here’s I would like to do :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public interface IMyService {
   void sum(int x, int y);
}

..

@WebService(serviceName=&quot;myService&quot;)
public class MyService implements IMyService {
...
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s a good starting point, but I like to say that the &lt;em&gt;MyService&lt;/em&gt; class is nothing but a default implementation of my service. Moreover, annotating a class leads to readability problems when you mix several annotation frameworks. So I wanted to be able to annotate &lt;em&gt;the interface&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@WebService
public interface IMyService {
  @WebMethod void sum(@WebParam(name=&quot;x&quot;) int x, @WebParam(name=&quot;y&quot;) int y);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then implement like this :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;@WebService(serviceName=&quot;myService&quot;)
public class MyService implements IMyService {
   public int sum(int x, int y) { return x+y; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This has multiple advantages :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;separation of interface and implementation (should &lt;strong&gt;always&lt;/strong&gt; be done)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the interface may be shared for both server endpoint and client stubs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Note that I must copy down the @WebService annotation just to specify the service name (as multiple services may implement the same interface). There, you should already see a problem, but let’s continue : Metro does not allow this. You cannot annotate interfaces and hope subclasses will be ``annotated&apos;&apos;. Bas point, but it’s rather logic :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package javax.jws;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.TYPE })
public @interface WebService
{
    String name() default &quot;&quot;;

    String targetNamespace() default &quot;&quot;;

    String serviceName() default &quot;&quot;;

    String wsdlLocation() default &quot;&quot;;

    String endpointInterface() default &quot;&quot;;

    String portName() default &quot;&quot;;
};&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The &lt;em&gt;@WebService&lt;/em&gt; annotation is not itself annotated with &lt;em&gt;@Inherited&lt;/em&gt;. Then, some weeks later, I moved to &lt;a href=&quot;https://incubator.apache.org/cxf/&quot;&gt;Apache CXF&lt;/a&gt;. To my surprise, although CXF uses the very same JAX-WS annotations, those annotations can be set on interfaces rather than classes ! How could it be ? Are annotations inherited or not ? My &lt;a href=&quot;https://www.jroller.com/melix/entry/the_truth_about_annotations_inheritance&quot;&gt;previous post&lt;/a&gt; gave you a technical yet simple answer : in that particular case, annotations are &lt;strong&gt;not inherited&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s where &lt;a href=&quot;https://www.closingbraces.net/&quot;&gt;Mike’s comment&lt;/a&gt; is interesting : it is a very complete explanation on why different frameworks did build their own annotations inheritance rules. To be clear, if an annotation has its retention policy set to runtime and is annotated with &lt;em&gt;@Inherited&lt;/em&gt;, then the subclasses with have this annotation to their annotations list too. But this does not prevent a framework from building its own inheritance policy.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In CXF, when you declare a class as a webservice, CXF looks for superclasses and interfaces to get those annotations. This is a &lt;strong&gt;framework dedicated annotation inheritance rule&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;With this second example, here you see the problem : although the &lt;strong&gt;technical truth&lt;/strong&gt; is that annotations are not inherited by default, the &lt;strong&gt;facts&lt;/strong&gt; are that frameworks define their own rules… Thanks Mike for giving me a great transition ;)&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>The truth about annotations inheritance</title>
      <link>https://melix.github.io/blog//2008/01/17/the_truth_about_annotations_inheritance.html</link>
      <pubDate>Thu, 17 Jan 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/01/17/the_truth_about_annotations_inheritance.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve read tons of articles about the subject : are annotations inherited or not ? Java 5 annotations are powerful, but you must understand what you do. Annotating a class does not necessarily mean that a subclass will keep the annotation. So, are they inherited or not ? The truth is that if you &lt;strong&gt;want&lt;/strong&gt; your annotations to be inherited, you &lt;strong&gt;must&lt;/strong&gt; specify it. Here’s a simple JUnit 4.4 test case to show you the concept.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package test.annotations;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Annotation;
import java.lang.annotation.Inherited;

public class AnnotationTest {

 @Retention(RetentionPolicy.RUNTIME)
 public @interface SimpleAnnotation {
  String value() default &quot;test&quot;;
 }

 @Retention(RetentionPolicy.RUNTIME)
 @Inherited
 public @interface InheritedAnnotation {
  String value() default &quot;test&quot;;
 }

 // two simple classes that will show that the annotation is *not* inherited
 @SimpleAnnotation
 class BaseClass {
 }

 class SubclassDoesNotInheritAnnotation extends BaseClass {
 }

 // two simple classes that will show that the annotation *is* inherited
 @InheritedAnnotation
 class InheritedBase {
 }

 class ChildInheritsAnnotation extends InheritedBase {
 }

 // proof
 @Test
 public void testAnnotations() {
  // not inherited
  Annotation[] annotations = BaseClass.class.getAnnotations();
  assertEquals(1, annotations.length);
  annotations = SubclassDoesNotInheritAnnotation.class.getAnnotations();
  assertEquals(0, annotations.length);

  // inherited
  annotations = InheritedBase.class.getAnnotations();
  assertEquals(1, annotations.length);
  annotations = ChildInheritsAnnotation.class.getAnnotations();
  assertEquals(1, annotations.length);
 }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The secret is the @Inherited annotation, which will ensure that subclasses will be annotated too.&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>IntelliJ IDEA&amp;#8217;s local history saved my life !</title>
      <link>https://melix.github.io/blog//2008/01/17/intellij_idea_s_local_history.html</link>
      <pubDate>Thu, 17 Jan 2008 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2008/01/17/intellij_idea_s_local_history.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One of my coworkers came to me quite stressed after having &lt;code&gt;accidently&apos;&apos; deleted source files from his project. The problem was that he had not done it from our editor, IntelliJ IDEA, but rather directly via windows explorer. Furthermore, he had also pressed &lt;/code&gt;shift+delete&apos;&apos;, which, for those who are not aware of that combination, means ``delete without possibility to recover&apos;&apos;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Damned. Not commit for the late two days (!), Windows XP, NTFS, shift+delete. My first thought was that he was screwed. Then we thought about the local history feature of Jetbrain’s editor. If there was a place where he could recover his files, there it was.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So we went to the &lt;code&gt;View &amp;#8594; Recent changes&apos;&apos; menu, and IDEA showed us a popup showing &lt;/code&gt;external changes&apos;&apos;. We clicked and thanks Jetbrains, the files were marked as deleted. We just had to select them, click on ``revert&apos;&apos; and voilà !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, Jetbrains did not saved my life. They saved his life ;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;P.S : I’m using Ubuntu Linux every day, and I have to admit the problem would have been the same : that’s not a windows related problem :)&lt;/p&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Separating configuration from deployment in web applications</title>
      <link>https://melix.github.io/blog//2007/12/26/separating_configuration_from_deployment_in.html</link>
      <pubDate>Wed, 26 Dec 2007 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2007/12/26/separating_configuration_from_deployment_in.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Since I write web applications, I’ve always been struggling with a very basic problem. Basically, I refuse to write, and tell my coworkers too, applications which require a compilation for each customer. This seems common sense, but it is really critical when building applications which require a high level of customization. The second problem is about &lt;strong&gt;upgrading applications&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_weakness_of_web_applications_containers&quot;&gt;The weakness of web applications containers&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Take Tomcat. Anyone who has ever deployed a &lt;em&gt;.war&lt;/em&gt; file knows that: deploying a war &lt;strong&gt;erases&lt;/strong&gt; everything in the exploded directory. This means that if you have made customizations in files located in WEB-INF directory (for example to configure your database), upgrading the application will make you loose all your configuration data. This has two implications:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;for the developer, this requires writing down a burn-proof upgrade guide which mostly consists of saying ``backup all your data and do what you’ve done for the first version another time&apos;&apos;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;for the customer, this leads to situations when you prefer not to upgrade because you &lt;strong&gt;fear the upgrade procedure&lt;/strong&gt; : you cannot allow breaking your system&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve personally seen both situations : as a developer, for my applications, and as a customer (upgrading Jira/Confluence), and lead me to find an alternative solution : &lt;strong&gt;allowing separation of configuration from binaries in a web environment in a system independent way&lt;/strong&gt;. Basically, the application should work out of the box, and you should never have to rewrite configuration files again.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_classloader_magics&quot;&gt;Classloader magics&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using Java, I’ve not found any cleaner way of reading configuration/resources any easier than using the classloader : it is an elegant system independent way of retrieving data. For example, you could get your configuration file this way :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public static final String PROPERTIES_FILE=&quot;/CONFIG/configuration.properties&quot;;

// ...

InputStream in = this.getClass().getResourceAsStream(PROPERTIES_FILE);
Properties props = new Properties();
try {
   props.load(in);
} catch (IOException e) {
   theLogger.warn(&quot;Unable to read configuration file &quot; + PROPERTIES_FILE, e);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This assumes that a file called &lt;em&gt;configuration.properties&lt;/em&gt; is accessible &lt;strong&gt;in the CONFIG directory at the root level in the classpath&lt;/strong&gt;. I think web environments miss some top level classpath directory convention like my &lt;em&gt;CONFIG&lt;/em&gt; directory. We have the &lt;em&gt;WEB-INF&lt;/em&gt; and &lt;em&gt;META-INF&lt;/em&gt; directories, but both are &lt;strong&gt;bundled with the application binaries&lt;/strong&gt;(&lt;em&gt;war&lt;/em&gt; file). I’d like to have, someday, a JSR which dynamically adds a &lt;em&gt;CONFIG&lt;/em&gt; directory in the application classpath. Application servers would be encouraged to separate this directory from the exploded one. For example, in a Tomcat environment, it would lead to the following directory structure :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tomcat/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tomcat/webapps&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tomcat/webapps/my-app&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tomcat/webapps-conf/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tomcat/webapps-conf/my-app&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The usual tricks that you do in the WEB-INF/classes directory would, therefore, be done in the webapps-conf/my-app directory. As this feature/standard is missing, I’ve been obliged to find a workaround using the Spring framework (but this could be reproduced in any web application).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_an_implementation_of_configuration_separation_using_spring&quot;&gt;An implementation of configuration separation using Spring&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_concept&quot;&gt;Concept&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Basically, I have implemented a fallback mechanism which allows fine grained configuration data finding procedure. When the application is bootstraping, it will look for its configuration files. If nothing is found, it will create a configuration directory and copy the default configuration files into it, then continue the boostrap using those files. I’ve chosen the following fallback mechanism (feel free to code your own), which targets at locating the &lt;em&gt;application home directory&lt;/em&gt;:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;if a properties file is accessible in the classpath, the application will look for a property in it which contains the application home directory&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;if a system property is set, then the application will read its home directory from it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the application creates its home directory in the &lt;em&gt;user home&lt;/em&gt; (that is the user which actually &lt;em&gt;runs&lt;/em&gt; the application server&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This mechanism allows multiple configurations : if you want to deploy your web application more than once on a single server, choose the first solution (agreed you’ll have to write &lt;strong&gt;one&lt;/strong&gt; file in the WEB-INF/classes directory). If you don’t need it, just export a system property before running the web application server. And finally, the simplest case is the last one, but in this case I strongly recommand that your web application user home directory is separated from the server binaries too. For example, under Linux, I usually run my Tomcat application server with its own user/group) (tomcat), but the tomcat user home &lt;strong&gt;must not&lt;/strong&gt; be the tomcat home. You should have something like this : /opt/tomcat : the application server /home/tomcat : the tomcat user home directory Doing this, upgrading the application server itself is easier, and you’ll never erase your configuration data. By the way, the solution I propose also allows you to share configuration across multiple web applications.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_spring_implementation&quot;&gt;Spring implementation&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The Spring implementation of this lookup algorithm makes use of the Spring &lt;em&gt;property placeholder&lt;/em&gt; concept: a property placeholder allows Spring to define properties programmatically which can be used in its configuration files. For example, you’ll have the following XML code :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;In the previous snippet, _$\{myproperty}_ is a property. The idea is to read all those properties from a custom property placeholder configurer and use them into our Spring configuration file. The good thing is that you can actually *use those properties for importing other Spring configuration files*, for example:

code,prettyprint---- code,prettyprint




...&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And the application configurer magic. In this case, we create two Spring configuration files, one called &lt;em&gt;applications.xml&lt;/em&gt; and the other named &lt;em&gt;generated.applications.xml&lt;/em&gt;. Both are real Spring configuration files :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;code,prettyprint&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt; code,prettyprint
public class ApplicationConfigurer extends PropertyPlaceholderConfigurer {
 private final static Logger theLogger = Logger.getLogger(ApplicationConfigurer.class);

 public static final String APPLICATION_HOME_PROPERTY = &quot;application.home&quot;;
        public static final String CUSTOM_APPLICATIONS_FILE = &quot;applications.xml&quot;;
 public static final String GENERATED_APPLICATIONS_FILE = &quot;generated.applications.xml&quot;;

 private static final String APPLICATION_HOME = &quot;.mycompany&quot;+File.separatorChar+&quot;myapp&quot;;
 private static final String APPLICATION_PROPERTIES_FILE = &quot;/myapp.properties&quot;;
 private static final String SAMPLE_APPLICATIONS_FILE = &quot;/com/mycompany/conf/applications.sample.xml&quot;;


 public ApplicationConfigurator() {

  // output generic version data
  theLogger.info(Version.getVersion());
  theLogger.info(&quot;(c) MyCompany 2007&quot;);

  String fultyHome = null;

  // search for application.properties file
  InputStream in = this.getClass().getResourceAsStream(APPLICATION_PROPERTIES_FILE);
  Properties props = new Properties();
  if (in != null) {
   try {
    props.load(in);
    setProperties(props);
    fultyHome = props.getProperty(APPLICATION_HOME_PROPERTY);
   } catch (IOException e) {
    in = null;
    theLogger.warn(&quot;Unable to read properties file &quot; + APPLICATION_PROPERTIES_FILE, e);
   }

  }

  if (in == null) { // search for system property
   fultyHome = System.getProperty(APPLICATION_HOME_PROPERTY);
   if (fultyHome == null) { // create default home
    fultyHome = System.getProperty(&quot;user.home&quot;) + File.separator + APPLICATION_HOME;
   }
   props.put(APPLICATION_HOME_PROPERTY, fultyHome);
   setProperties(props);
  }

  theLogger.info(&quot;Using APPLICATION_HOME : &quot; + fultyHome);
  File homeDir = new File(fultyHome);
  createDefaults(homeDir);

 }

 private void createDefaults(File aHome) {
  if (!aHome.exists()) {
   theLogger.info(aHome + &quot; does not exist. Creating default files&quot;);
   aHome.mkdirs();
  }
  File appFile = new File(aHome, CUSTOM_APPLICATIONS_FILE);
  if (!appFile.exists()) {
   theLogger.info(&quot;Configuration &quot;+ CUSTOM_APPLICATIONS_FILE +&quot; does not exist. Using defaults file.&quot;);
   theLogger.info(&quot;Please edit &quot; + appFile.getAbsolutePath() + &quot; then restart the application&quot;);
   URL url = this.getClass().getResource(SAMPLE_APPLICATIONS_FILE);
   File src = new File(url.getFile());
            copySampleFile(appFile, src);
            copySampleFile(new File(aHome, GENERATED_APPLICATIONS_FILE),src);
        }
 }

    private void copySampleFile(File aAppFile, File aSrc) {
        try {
            FileOutputStream out = new FileOutputStream(aAppFile);
            FileInputStream in = new FileInputStream(aSrc);
            in.getChannel().transferTo(0, aSrc.length(), out.getChannel());
            in.close();
            out.close();
        } catch (IOException e) {
            theLogger.error(&quot;Unable to copy default applications file&quot;,e);
        }
    }


}
-------------------------------------------------------------------------------------------------------

That’s all ! This class creates a single property called _application.home_ that may be used in your Spring configuration file. As I said before, you could read more that one property and create a whole set of properties to be used in your Spring configuration file, but as I also split my Spring configuration files and the lack of property exports to child contexts, the only property I export is the application home, so that *other beans can programatically create Spring contexts*.

[[]]
Conclusion
----------

This post showed you that you could, at level design, avoid some lacks to the Java web application frameworks which makes it rather complex to separate configuration data from the application itself. This is a low cost implementation which demonstrates that it is not necessarily costly to think about it, and that it is, to my mind, something that *should always be done* because it *simplifies maintenance*.&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>GFreeMarker 0.2 released</title>
      <link>https://melix.github.io/blog//2007/12/21/gfreemarker_0_2_released.html</link>
      <pubDate>Fri, 21 Dec 2007 00:00:00 +0100</pubDate>
      <guid isPermaLink="false">2007/12/21/gfreemarker_0_2_released.html</guid>
      	<description>
	&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I have released a new version of &lt;a href=&quot;https://groovy.codehaus.org/GFreeMarker&quot;&gt;GFreeMarker&lt;/a&gt;, an integration of the FreeMarker template engine in Groovy. This release has no functional change, but has been refactored :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Built made by Maven 2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compatibility with JDK 1.4&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Uses Groovy 1.5&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>FreeMarker for Groovy</title>
      <link>https://melix.github.io/blog//2007/08/03/freemarker_for_groovy.html</link>
      <pubDate>Fri, 3 Aug 2007 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2007/08/03/freemarker_for_groovy.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;After finding out that &lt;a href=&quot;https://www.jroller.com/melix/entry/replacing_velocity_with_groovy_jsmarty&quot;&gt;Groovy templates would be great as a replacement for Velocity&lt;/a&gt;, then thinking about &lt;a href=&quot;https://www.jroller.com/melix/entry/grails_spring_and_templates_security&quot;&gt;security issues&lt;/a&gt;, I came to a third solution.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_freemarker_for_groovy&quot;&gt;FreeMarker for Groovy&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Some of you told me that I could take a look at FreeMarker, as a practical replacement for Velocity. I went on, but seen nothing that would fit my needs : beeing able to dynamically add &lt;code&gt;tags&apos;&apos; or &lt;/code&gt;plugins&apos;&apos; to a customer template. I mean I would not need to rebuild and redeploy an application just to get a simple plugin working. Then I thought I would be able to create a &lt;a href=&quot;https://fmpp.sourceforge.net/freemarker/pgui_datamodel_transform.html&quot;&gt;transform&lt;/a&gt; for FreeMarker that would make the benefits of the FreeMarker template engine available for Groovy. Basically, it would fit my needs :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Beeing able to dynamically add plugins for a customer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fix does nasty security issues by making the web designer unable to directly write Groovy code (the programmer creates plugins, then makes them available to a customer)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_does_it_work&quot;&gt;How does it work ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine your customer requires an URL Encoding text transform, and that FreeMarker does not offer this possibility. Then, you would just need to :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Create a plugin named &lt;em&gt;urlencoder&lt;/em&gt; that implements the &lt;em&gt;IGroovyFreeMarkerPlugin&lt;/em&gt; interface&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy this plugin into the Groovy FreeMarker template engine plugins directory&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Tell your customer how to use it :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;&amp;lt;@groovy plugin=&quot;urlencoder&quot;&amp;gt;this is an expression that will be converted to its URL Encoding form&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The FreeMarker engine will then call your plugin and return the transform. Note that you may embed FreeMarker tags and variables : the transform content does not need to be plain text. For example :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;&amp;lt;@groovy plugin=&quot;urlencoder&quot;&amp;gt;this is an ${expression} that will be converted to its URL Encoding form&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Now take a look a the plugin code itself:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.text.freemarker.IGroovyFreeMarkerPlugin

class urlencoder implements IGroovyFreeMarkerPlugin {
 String transform(Map params, String content) {
  URLEncoder.encode(content);
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s a sample groovy script that will show you how you can use the template engine :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.text.freemarker.FreeMarkerTemplateEngine

def tpl = &apos;&apos;&apos;
Hello, ${user.name}
&amp;lt;@groovy plugin=&quot;urlencoder&quot; mode=user&amp;gt;this is a test ${user.name}&apos;&apos;&apos;
def engine = new FreeMarkerTemplateEngine(&quot;plugins&quot;)
def binding = [&quot;user&quot; : [&quot;name&quot;:&quot;cedric&quot;]]
println engine.createTemplate(tpl).make(binding)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_default_implementation_bonuses&quot;&gt;Default implementation bonuses&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve built a rather simple implementation, but it still has some additional features:&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Template caching: instead of using the &lt;em&gt;createTemplate()&lt;/em&gt; method, use the &lt;em&gt;createNamedTemplate()&lt;/em&gt; one first. It will create a template and put it into the template cache, then use the &lt;em&gt;getNamedTemplate()&lt;/em&gt; method to retrieve a cached template.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Plugin loader: there’s a default implementation which reads plugins from a directory. Feel free to implement the &lt;em&gt;IGroovyFreeMarkerPluginLoader&lt;/em&gt; if you want more complex loaders&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Plugin parameters: if the &amp;lt;@groovy&amp;gt; tag content is not sufficient, you may add parameters to the transform, and use them in the plugin thanks to the params map. For example : &amp;lt;@groovy plugin=&lt;code&gt;temperatureconvertor&apos;&apos; source=&lt;/code&gt;celcius&apos;&apos; dest=``kelvin&apos;&apos;&amp;gt;112&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_grabbing_the_code&quot;&gt;Grabbing the code&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Binary: &lt;a href=&quot;https://cedric.champeau.free.fr/freemarker/gfreemarker-0.1.0.jar&quot;&gt;gfreemarker-0.1.0.jar&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Javadoc: &lt;a href=&quot;https://cedric.champeau.free.fr/freemarker/gfreemarker-javadoc.zip&quot;&gt;gfreemarker-javadoc.zip&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sources (with IntelliJ IDEA project): &lt;a href=&quot;https://cedric.champeau.free.fr/freemarker/GroovyFreeMarker.tar.gz&quot;&gt;GroovyFreeMarker.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You will also need the latest &lt;a href=&quot;https://cedric.champeau.free.fr/freemarker/freemarker.jar&quot;&gt;freemarker.jar&lt;/a&gt;. I will not have much time to work on this, so feel free to contribute !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Grails, Spring and templates security issue example</title>
      <link>https://melix.github.io/blog//2007/08/02/grails_spring_and_templates_security.html</link>
      <pubDate>Thu, 2 Aug 2007 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2007/08/02/grails_spring_and_templates_security.html</guid>
      	<description>
	&lt;div id=&quot;preamble&quot;&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In my &lt;a href=&quot;https://www.jroller.com/melix/entry/replacing_velocity_with_groovy_jsmarty&quot;&gt;previous post&lt;/a&gt;, I was thinking about using Groovy SimpleTemplateEngine as a replacement for Velocity. The main idea was to be able to create arbitrary functions for use in the template without having to rebuild my application (and expose a utility class). I’ve been told about taking a look at &lt;a href=&quot;https://freemarker.org&quot;&gt;&lt;em&gt;FreeMarker&lt;/em&gt;&lt;/a&gt;, but the problem is quite the same : some operations may not be written by a web designer. I’ll take a simple example : for a customer, we needed to be able to take a simple string, and convert it in an URL encoded string. To do that, I had to expose and utility tool which was able to do URL encoding, and rebuild and application. As far as I have seen, FreeMarker functions do not allow that kind of manipulation either (I &lt;em&gt;may&lt;/em&gt; be wrong, feel free to correct me).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_security_issue&quot;&gt;Security issue&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;However, the goal of this post is to show you why mixing code with templates is generally a bad idea, however powerful the technique may be. As best example, I’ll show you a major security issue with using both &lt;em&gt;Spring&lt;/em&gt; and &lt;em&gt;Groovy.&lt;/em&gt; I’ve chosen Spring because most of my applications use this framework, and I’m quite confident yours too.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;First, we’ll write a simple service, which should never be exposed to the end user. Its goal is to retrieve my list of credit card numbers, in order to be able to choose which one I’ll use to buy my PS3 system.&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;package com.example;

public class MyPrivateService {
    private String[] theCreditCardNumbers;

    public String[] getCreditCardNumbers() {
        return theCreditCardNumbers;
    }

    public void setCreditCardNumbers(String[] someCreditCardNumbers) {
        theCreditCardNumbers = someCreditCardNumbers;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;And the following Spring configuration :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s a sample Groovy script that shows you how this could be used in your application :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import org.springframework.beans.factory.BeanFactory
import org.springframework.beans.factory.xml.XmlBeanFactory
import org.springframework.core.io.ClassPathResource


// setup Spring Application Context
def beanfactory = new XmlBeanFactory(new ClassPathResource(&quot;com/example/applicationContext.xml&quot;))

// print credit card numbers
def creditCardService = beanfactory.getBean(&quot;creditCardService&quot;)

creditCardService.creditCardNumbers.each {
 println it;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;which outputs :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;1114-554112-01115
1151-45454-454490&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Imagine my service is for pure internal usage, and that it must NEVER EVER be exposed to the public. However, in some other part of your web application, there’s a front end page which may be customized (themed) thanks to the Groovy template engine. This allows the customer to create his own theme, granted he writes a good looking HTML page. The user could write something as simple as :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Hello, M. ${user.name} !&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;You may think that your system is secure, because you only exposed the &lt;em&gt;User&lt;/em&gt; bean to your template :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.text.SimpleTemplateEngine

class ProofOfConceptController {

 def index = {
  def template = &apos;&apos;&apos;
   &amp;lt;%  def content = new StringBuffer();
    def beanfactory = new org.springframework.beans.factory.xml.XmlBeanFactory(
     new org.springframework.core.io.FileSystemResource(&quot;spring/resources.xml&quot;))
    beanfactory.beanDefinitionNames.each {
     content &amp;lt;&amp;lt; &quot;Bean named $it defined in application context&quot;;
     content &amp;lt;&amp;lt; &quot;&quot;
     def bean = beanfactory.getBean(it)
     bean.properties.each {
      content &amp;lt;&amp;lt; &quot;$it&quot;
     }
     content &amp;lt;&amp;lt; &quot;&quot;
    }
   %&amp;gt;
            $content
  &apos;&apos;&apos;;
  def binding = [&quot;user&quot; : &quot;cedric&quot;]
  def engine = new SimpleTemplateEngine()
  [&quot;rendered&quot; : engine.createTemplate(template).make(binding)]
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s the output :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;Bean named creditCardService defined in application context

    * metaClass=org.codehaus.groovy.grails.commons.metaclass.ExpandoMetaClass@ea7776[class com.example.CreditCardService]
    * transactional=true
    * creditCardNumbers=[Ljava.lang.String;@4e94a4
    * class=class com.example.CreditCardService&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Using this Grails controller, the user will be able to browse all beans defined within the traditional ``resources.xml&apos;&apos; Grails file !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_how_does_it_work&quot;&gt;How does it work ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This proof-of-concept assumes that the user knowns about the underlying technology : Grails. Using this, you can grab the user defined application context (resources.xml) in order to list all beans. With the previous template, the hacker could find out interesting beans and properties. Now he should just adapt the template to read the &lt;em&gt;creditCardService&lt;/em&gt; property named &lt;em&gt;creditCardNumbers&lt;/em&gt;… Well, I must admit this is rather tricky : the hacker has to know about the Grails internals, but sure this example could be adapted to other web applications. Spring provides a useful but risky class called &lt;em&gt;WebApplicationContextUtils&lt;/em&gt; which allows, given a session, retrieving the application context. Therefore if the session (that’s the tough part) is avaible &lt;strong&gt;to the template&lt;/strong&gt;, one could hack the system. Fortunately, it is unlikely that the programmer makes the session available to the template, and we must encourage not to do so.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve just showed you how one could use Groovy templates in order to hack a system or steal information. The problem resides in the mixed environment where the hacker has access to the same static utility methods as the programmer, in the same JVM. Therefore, if you cannot isolate the template engine from the rest of the system (I wonder how it could be done), you must really be careful about what you do…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Replacing Velocity with Groovy = JSmarty ?</title>
      <link>https://melix.github.io/blog//2007/08/01/replacing_velocity_with_groovy_jsmarty.html</link>
      <pubDate>Wed, 1 Aug 2007 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2007/08/01/replacing_velocity_with_groovy_jsmarty.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_templating_languages_as_first_choice_technology_for_front_end_customization&quot;&gt;Templating languages as first choice technology for front-end customization &lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’m not fond of JSF-like front end technologies. I mean, for anyone who’s used to templating technologies such as Smarty for PHP, using JSF is masochism : crying things like you can’t just iterate over a simple collection. With JSF, you must understand the underlaying philosophy and the technology before you succeed in doing something as simple as echoing a set of records. Too complicated for simple designs, and, nonetheless, unusable by a web designer (I mean someone who’s able to write HTML, but knows almost nothing of programming).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;That’s why I like templating technologies : simplicity, and with a good application design, you won’t break the MVC model. Customizing a web design for the needs of a customer would not require anything else than changing a few front-end templates. For this I’ve been using Apache Velocity in Java, while in PHP I was used to Smarty.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_velocitys_main_drawback&quot;&gt;Velocity’s main drawback &lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;But Velocity does not offer the softness Smarty has : imagine your web designer needs a date format tag in order to pretty print a date variable. In Smarty, you just need to write a plugin (ok, for dates it is just included ;-)), and it is straight available in your templates. With Velocity, you must imagine all usages of the variables or objects you expose before you make a template. I mean that you must think that a web designer would like to format a date, then expose the date utility to the template.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In this case, in order to be sure you won’t forget anything, you could simply expose all of your utility classes to the template, but this is fondamentaly unnecessary, ugly and you could possibly never imagine everything a template writer could need. The problem is right there : with Velocity, if you did not think of something at the design time, then it will not be possible to do at runtime, just because template variables and utility classes are exposed programmatically. It is just right for variables, but a problem for utility classes. That’s the main drawback I found to Velocity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then came Groovy and its SimpleTemplateEngine. Basically, it does the very same as Velocity for templating, but its main advantage is that you can embed groovy code &lt;em&gt;into&lt;/em&gt; the template :&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import groovy.text.SimpleTemplateEngine

def tpl_src =&apos;&apos;&apos;
&amp;lt;% def formatDate(date) {
    new java.text.SimpleDateFormat(&quot;EEE, MMM d, &apos;&apos;yy&quot;).format(date)
}%&amp;gt;

The date today is &amp;lt;% print formatDate(date) %&amp;gt;&apos;&apos;&apos;

def binding = [ &quot;date&quot;: Calendar.getInstance().getTime() ]
def engine = new SimpleTemplateEngine()
println engine.createTemplate(tpl_src).make(binding)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Just as simple as that ! You won’t need to rebuild an application in order to make an utility class, which has fundamentally nothing to do with the application logic, available to a template (front end logic). That’s where I liked Smarty so much, and makes me think I should actually think of replacing my Velocity templates with Groovy ones.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_should_i_move&quot;&gt; Should I move ?&lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well, before moving, I’ll have to double check things like :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;performance : how does Groovy templates compare to Velocity (Smarty has this caching thing)?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;template inclusion : how can I manage template inclusions like velocity does ?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;security : beeing able to run arbitrary code in the template may not be a &lt;em&gt;so good idea&lt;/em&gt;…&lt;br&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Well I have a semi-answer for the last one : GSP pages, built upon Groovy, seem to have a tag, but GSP’s are part of the grails framework, which is too large for this particular need.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;What do you think ?&lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>
    <item>
      <title>Dynamic database models with Groovy and Hibernate</title>
      <link>https://melix.github.io/blog//2007/07/26/dynamic_database_models_with_groovy.html</link>
      <pubDate>Thu, 26 Jul 2007 00:00:00 +0200</pubDate>
      <guid isPermaLink="false">2007/07/26/dynamic_database_models_with_groovy.html</guid>
      	<description>
	&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_the_problem&quot;&gt;The problem &lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;I’ve been working some time with Hibernate and been quite happy with it. However, for one of the projects I’m working on, I’ve been facing a problem Hibernate could not manage alone. The main idea was just to migrate an existing database from MySQL to an ORM DB independent through Hibernate.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Independently of the various compatibility problems which I should not address now, this project had a major difference with traditionnal database modelling : the application works with a different database for each customer, and each database has its own model (at least for some tables). Deploying for a customer does not require compiling a new application. Let’s come with an example.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;In documentary management, a document can be described as a set of fields :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt; Document(title, abstract, subject, body)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt; While some of those fields fit for every customer, working on specific documents require more fields. For example :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt; Document(title,abstract, subject, body, category)&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;where category is a custom field. &lt;br&gt;
 &lt;br&gt;
 Generally, if you are used to Hibernate, you may think the problem can be solved with a simple bean where all fields are stored as a map :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt; public class Document {
    private int theID;
    private Map theCustomFields;
    /* ...  here comes the getters/setters */
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;literalblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre&gt;+
There are two problems with this model :&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;ulist&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;types of properties are defined at compile time, and cannot be changed (property name type is String, but the property value is also. What if you want to store a boolean ?) &lt;br&gt;
 - Hibernate will generate two tables : one for the document, and the other one for the custom fields values.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt; This is surely not what we want : the existing model just consists of a simple &lt;em&gt;document&lt;/em&gt; table for which all columns refer to a document property (aka custom field). This is both much simpler to read and does not require any join in order to read all the fields of a single document. &lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This ``limitation&apos;&apos; of Hibernate just meant that I would not be able to migrate the database without changing its schema. In my case, this was just problematic as I could not upgrade the database schema, too many different components, written in several languages (Java, Perl, …) could write or read this database.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect1&quot;&gt;
&lt;h2 id=&quot;_groovybernate&quot;&gt;Groovybernate ! &lt;/h2&gt;
&lt;div class=&quot;sectionbody&quot;&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Therefore, I’ve been searching for a solution, and thought about dynamic bean generation. I’ve had read about the dynamic language Groovy, and decided to take a look. As it produces 100% Java compatible bytecode, I thought it would just fit for Hibernate. It took not very long to find out that I would be able to do what I wanted : &lt;strong&gt;achieving maximum database flexibility thanks to Groovy and Hibernate&lt;/strong&gt;. This means runtime modification of the model, and optimum performance (no joins whatsoever for just bean properties). &lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_how_does_it_work&quot;&gt; How does it work ?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;From Groovy 1.1 (still in beta stages), you may use annotations. That sounded good for me as I’ve always been using Hibernate Annotations in my projects. The idea was just to dynamically create an Annotated Java Bean from a description file, then make Hibernate aware of this class and &lt;em&gt;voilà&lt;/em&gt; !&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;The following consists of a simple Proof-Of-Concept. Instead of using a configuration file for describing the model, we’ll just do it programmatically. Then we’ll show how to use this model in order to dynamically create a Groovy class, create instances of it through Java and, eventually, persist it &lt;em&gt;via&lt;/em&gt; Hibernate. &lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_why_not_pure_groovy&quot;&gt; Why not pure Groovy ?&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;One could say that if I’ve managed to do this with Java and Groovy code mixed up, then I could’ve done it in pure Groovy. True. But I still remember that Groovy is a dynamic language loosely typed, which, therefore, does not offer the same compile-time security one could have with pure Java. I’m using IntelliJ IDEA every day for developpement, and not beeing able to say if your code is valid statically with Groovy is just a source of bunches of bugs, especially when you are using plents of third party libs. The following POC has been made with IntelliJ IDEA and the latest Groovy 1.1 beta 2, which allows compiling both Java and Groovy code at once, mixing up both languages without caring about cyclic dependencies. To be honest, my first trial was made with the beta 1 which did not offer this, and it was just more complicated : you had to separate 3 trees of source code : one for pure Groovy, one for pure Java, and the latest one is an interoperability set of Java interfaces and enumerations that allows the other two to communicate. Hopefully the Jetbrain guys went off this and provided us a new version of the compiler, and you should not have to do those (dirty but necessary) tricks. Note that using IntelliJ IDEA is not necessary. However, as the latest EAP offers an outstanding Groovy support, I strongly suggest that you take a look ;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To conclude, mixing up Java and Groovy code is just a mean of having the best of the two worlds : security of strongly typed Java and flexibility of dynamic Groovy. This just makes the best thing I’ve ever programmed in my life, that’s truly groovy !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_preparing_the_model_with_meta_description&quot;&gt;Preparing the model with meta description&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;If I wish to be able to dynamically generate beans, the best idea is to have a meta description of my bean. If you are aware of Groovy, you could think about the ExpandoMetaClass which allows to dynamically add properties/methods on an object. However, we could not manage to use it in this case, because we needed to dynamically annotate the class and its properties. Groovy 1.1 supports annotations, but is not yet able to dynamically add annotations to classes or members (if I’m wrong, tell me now !).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;So I went by creating my own simplified meta model. Here’s the code (Java) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class MetaClass {
 private boolean isEntity = true;
 private String theParentClass;
 private String theName;
 private String theTableName;
 private Map&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This meta class allows describing a bean which should be persisted by Hibernate. We need to be able to describe the class fields too (Java) :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class MetaField {
 private String theName;
 private boolean isPK;
 private MetaType theType;


 public MetaField() {
 }

 public MetaField(String aName, boolean aPK, MetaType aType) {
  theName = aName;
  isPK = aPK;
  theType = aType;
 }

 public String getName() {
  return theName;
 }

 public void setName(String aName) {
  theName = aName;
 }

 public boolean isPK() {
  return isPK;
 }

 public void setPK(boolean aPK) {
  isPK = aPK;
 }

 public MetaType getType() {
  return theType;
 }

 public void setType(MetaType aType) {
  theType = aType;
 }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Then eventually, a set of meta types, with their Hibernate translation :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public enum MetaType {
 STRING(&quot;String&quot;),
 INT(&quot;Integer&quot;),
 LONG(&quot;Long&quot;),
 DOUBLE(&quot;Double&quot;),
 DATETIME(&quot;@Date Date&quot;),
 DATE(&quot;@Temporal(TemporalType.DATE) Date&quot;),
 TEXT(&quot;@Column(length = 2147483647) String&quot;);

 String theHibernateConversion;

 MetaType(String aStringValue) {
  theHibernateConversion = aStringValue;
 }

 public String getHibernateConversion() {
  return theHibernateConversion;
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, let’s see now how we programmatically describe a bean :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;MetaClass meta = new MetaClass(cl);
meta.setName(&apos;test&apos;);
meta.addField(new MetaField(&quot;title&quot;, false, MetaType.STRING));
meta.addField(new MetaField(&quot;date&quot;, false, MetaType.DATE));&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Easy, isn’t it ? You may be wondering why we must provide a GroovyClassLoader. This is something that I’ve been working with since the beginning, without cleaner solution : in order to be able to get a class instance which is both recognized by Groovy and Hibernate, Groovy must be the parent class loader…&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_generating_a_groovy_bean&quot;&gt;Generating a groovy bean&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, this is the core trick : now that we have a meta description of a class, we need to translate it to a real Java Class object. This implies compiling our meta class into real bytecode. As we cannot use the ExpandoMetaClass, we’ll do it through dynamic code generation. As this kind of stuff is much easier to both write and read in the Groovy language (get it ? the best of the two worlds !), we’ll write it in Groovy. That’s where the old cyclic dependencies come : notice how we’ll use the MetaClass class which we’ve written in Java, while the Java code will have to be able to access this bean generator class, written in Groovy… Ugly enough, before beta 2, I had to write interfaces for all those objects which are shared between the two (and you’ll reckon that writing interfaces for beans is somehow… ridiculous). So here’s the core groovy bean generator (Groovy) : &lt;br&gt;
 &lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;import MetaClass
import groovy.text.Template
import groovy.text.SimpleTemplateEngine
class GroovyBeanGenerator {
 public String getBeanSource(MetaClass meta) {
  def tpl_src = &apos;&apos;&apos;import javax.persistence.*;

&amp;lt;% if (meta.isEntity) { %&amp;gt;
@Entity(name=&quot;${meta.tableName}&quot;)
&amp;lt;%}%&amp;gt;
class ${meta.name} &amp;lt;% if (meta.parentClass!=null) { %&amp;gt; extends ${meta.parentClass} &amp;lt;%}%&amp;gt;{
&amp;lt;% for (entry in meta.fields) {
 def field = entry.value
 print &quot;    &quot;;
 if (field.isPK) print &quot;@Id &quot;;
 println &quot;${field.type.hibernateConversion} ${field.name}&quot;
}%&amp;gt;
}
  &apos;&apos;&apos;
  def binding = [ &quot;meta&quot;: meta ]
  def engine = new SimpleTemplateEngine()
     def template = engine.createTemplate(tpl_src).make(binding)
     return template.toString();
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;It works by defining a Groovy template, which is just a Groovy bean class code. Note that this code could surely be written shorter thanks to closures, but I’d rather keep it simple for newcomers. The goal of this class is just to generate source code for our bean. This bean is annotated with Hibernate Annotations. Now, we’ll write the simple Java bunch of code which will allow us to create instances of this bean and register them in Hibernate.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_groovybernateutil_for_dynamic_registration_of_beans&quot;&gt;GroovybernateUtil for dynamic registration of beans&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;This class will do two things (ok, we could have splitted them apart) : create instances of beans using the groovy bean generator and manage the Hibernate session.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class GroovybernateUtil {
 private String theApplicationName;
 private AnnotationConfiguration theConfiguration;
 private boolean isModelUpdated;
 private SessionFactory theSessionFactory;
 private GroovyClassLoader theClassLoader;

 public GroovybernateUtil(GroovyClassLoader aClassLoader, String aApplicationName, String aDialect, String aDriver, String anUrl, String aUsername, String aPassword) {
  theClassLoader = aClassLoader;
  theApplicationName = aApplicationName;
  theConfiguration = (AnnotationConfiguration) new AnnotationConfiguration()
   .setProperty(&quot;hibernate.dialect&quot;, aDialect)
   .setProperty(&quot;hibernate.connection.driver_class&quot;, aDriver)
   .setProperty(&quot;hibernate.connection.url&quot;, anUrl)
   .setProperty(&quot;hibernate.connection.username&quot;, aUsername)
   .setProperty(&quot;hibernate.connection.password&quot;, aPassword)
//   .setProperty(&quot;hibernate.generate_statistics&quot;, &quot;true&quot;)
   .setProperty(&quot;hibernate.hbm2ddl.auto&quot;, &quot;create-update&quot;);
//   .setProperty(&quot;hibernate.hbm2ddl.auto&quot;, &quot;create-drop&quot;);
        isModelUpdated = true;
 }

 public Session getSession() {
  if (isModelUpdated) updateSessionFactory();
  return theSessionFactory.openSession();
 }

 private void updateSessionFactory() {
  theSessionFactory = theConfiguration.buildSessionFactory();
  isModelUpdated = false;
 }

 public String getApplicationName() {
  return theApplicationName;
 }

 public void setApplicationName(String aApplicationName) {
  theApplicationName = aApplicationName;
 }


 public void registerGroovyBean(Class aBeanClass) {
  theConfiguration.addAnnotatedClass(aBeanClass);
 }

 public void registerGroovyBean(String aBeanClass) throws ClassNotFoundException {
  theConfiguration.addAnnotatedClass(theClassLoader.loadClass(aBeanClass));
 }

 public void registerGroovyBeanSource(InputStream aBeanSource) {
  theConfiguration.addAnnotatedClass(theClassLoader.parseClass(aBeanSource));
 }

 public Statistics getStats() {
  return theSessionFactory.getStatistics();
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Anyone who’ll need to work with a dynamic database model should use this simple utility class in order to create an Hibernate session that will be aware of dynamic beans. We’re done !&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_make_it_run_together&quot;&gt;Make it run together&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Ok, you’ve read a bunch of code, and now, I assume you’ll want to test it by yourself, and, surely, you’ll want to see how you’ll be able to create instances of thoses beans, set their properties and so on. Hopefully, each object instanciated in groovy inherits the GroovyOject interface, which provides the getters/setters we need.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Here’s the simple test code. It reads a large CSV file which should be persisted in database. The CSV columns refer to bean properties, while rows are instances :&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;listingblock&quot;&gt;
&lt;div class=&quot;content&quot;&gt;
&lt;pre class=&quot;prettyprint highlight&quot;&gt;&lt;code&gt;public class Groovybernate {
 public static void main(String[] args) throws IllegalAccessException, InstantiationException {

  GroovyClassLoader cl = new GroovyClassLoader(Groovybernate.class.getClassLoader());
  Thread.currentThread().setContextClassLoader(cl);
  GroovybernateUtil util = new GroovybernateUtil(cl, &quot;test&quot;,
    &quot;org.hibernate.dialect.MySQL5Dialect&quot;,
    &quot;com.mysql.jdbc.Driver&quot;,
    &quot;jdbc:mysql://localhost:3306/hibertest&quot;,
    &quot;test&quot;,
    &quot;password&quot;);
  MetaClass meta = new MetaClass(cl);
  meta.setName(&quot;test&quot;);
  meta.setTableName(&quot;test&quot;);
  meta.addField(new MetaField(&quot;id&quot;, true, MetaType.INT));
  meta.addField(new MetaField(&quot;c1&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c2&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c3&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c4&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c5&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c6&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c7&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c8&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c9&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c10&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c11&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c12&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c13&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c14&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c15&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c16&quot;, false, MetaType.STRING));
  meta.addField(new MetaField(&quot;c17&quot;, false, MetaType.STRING));
  try {
   util.registerGroovyBean(meta.getBeanClass());
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
  Session session = util.getSession();
  Transaction tx = session.beginTransaction();
  long sd = Calendar.getInstance().getTimeInMillis();
  BufferedReader reader = null;
  try {
   reader = new BufferedReader(new FileReader(&quot;resources/large.csv&quot;));
  } catch (FileNotFoundException e) {
   e.printStackTrace();
  }
  int loop = 0;
  try {
   String line = reader.readLine();
   while (line != null) {
    try {
     loop++;
     String[] values = line.split(&quot;:::&quot;);
     GroovyObject bean = meta.newInstance();
     bean.setProperty(&quot;vid&quot;, loop);
     for (int i = 0; i &amp;lt; 17; i++) {
      bean.setProperty(&quot;c&quot; + (i + 1), values[i]);
     }
     session.save(bean);
     if (loop % 10000==0) {
      System.out.println(&quot;Committed &quot;+loop+&quot; records...&quot;);
      session.flush();
      session.clear();
     }
    } catch (ClassNotFoundException e) {
     e.printStackTrace();
    }
    line = reader.readLine();
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
  tx.commit();

  long ed = Calendar.getInstance().getTimeInMillis();
  double duration = ((ed - sd) / 1000);
  double persec = ((double) loop / duration);
  double perhour = 3600 * persec;
  System.out.println(MessageFormat.format(&quot;Processed {0} elements in {1} seconds ({2} records/h)&quot;, loop, duration, perhour));
//  Statistics stats = util.getStats();

 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;sect2&quot;&gt;
&lt;h3 id=&quot;_conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;To conclude, we’ve been able to perform what we wanted to do : to dynamically generate a bean from a meta description, which could be easily read from a configuration file, in order to achieve maximum flexibility in database schema customization. This allows customizing some objects of an application for customer needs, without needing to update an existing database schema (our need), with human readable database objects (one table per bean, instead of two tables, one for instances, the other for its properties) and very good performance. I hope this has given you some ideas about how you can go beyond the ``limitations&apos;&apos; of a static Hibernate object model without breaking the logic behind. I mean that with this solution, what should be pure configuration (database customization for customer needs) remains configuration without breaking the rules of ORM. If I had wanted to perform such without Groovy, I would have been obliged to compile a dedicated application for each customer, which is both unnecessary and completely illogic. Moreover, any change in the model would require building a new application…&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;paragraph&quot;&gt;
&lt;p&gt;Comments welcome ;) &lt;br&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
	</description>
    </item>

  </channel> 
</rss>
