<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.f1re.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.f1re.io/" rel="alternate" type="text/html" /><updated>2026-10-13T11:32:38+00:00</updated><id>https://www.f1re.io/feed.xml</id><title type="html">F1RE Technology Blog</title><subtitle>Technical articles from F1RE engineers on Model-Driven Engineering, Domain-Specific Languages, JetBrains MPS, LionWeb and SysML v2.</subtitle><author><name>F1RE</name><email>atanas@f1re.io</email></author><entry><title type="html">Quieting JUL Warnings That Maven Tags as [ERROR]</title><link href="https://www.f1re.io/2026-06-30/quieting-jul-warnings-in-maven-logs" rel="alternate" type="text/html" title="Quieting JUL Warnings That Maven Tags as [ERROR]" /><published>2026-06-30T00:00:00+00:00</published><updated>2026-06-30T00:00:00+00:00</updated><id>https://www.f1re.io/2026-06-30/quieting-jul-warnings-in-maven-logs</id><content type="html" xml:base="https://www.f1re.io/2026-06-30/quieting-jul-warnings-in-maven-logs"><![CDATA[<div id="toc" class="toc">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#problem">Problem</a></li>
<li><a href="#cause">Cause</a></li>
<li><a href="#solution-a-level-based-filter">Solution A: Level-based filter</a></li>
<li><a href="#solution-b-stream-redirect-via-custom-handler">Solution B: Stream redirect via custom handler</a></li>
<li><a href="#trade-off">Trade-off</a></li>
<li><a href="#consequence-jvm-argument-propagation">Consequence: JVM argument propagation</a></li>
<li><a href="#consequence-the-picked-up-java_tool_options-message">Consequence: the <code>Picked up JAVA_TOOL_OPTIONS</code> message</a></li>
<li><a href="#consequence-the-two-line-log-format">Consequence: the two-line log format</a></li>
<li><a href="#result">Result</a></li>
</ul>
</div>
<div class="paragraph">
<p>This post describes a small problem in a Maven+Ant based MPS build:
several JUL (Java Util Logging<sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnotedef_1" title="View footnote.">1</a>]</sup>)
warnings emitted by MPS during headless generation end up prefixed with <code>[ERROR]</code> in the CI log.
The build succeeds though.
The mislabelling makes real errors harder to spot.
Below, we walk through why it happens, two ways to fix it, and the trade-offs each fix brings.</p>
</div>
<div class="sect1">
<h2 id="problem">Problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In a headless MPS build driven by Maven with the maven-antrun-plugin, several loggers inside MPS emit informational messages at <code>WARNING</code> level.
They are using <code>java.util.logging</code>&#8201;&#8212;&#8201;commonly abbreviated JUL&#8201;&#8212;&#8201;the logging framework built into the JDK.
Examples include <code>jetbrains.mps.classloading.ModulesWatcher</code>, <code>jetbrains.mps.persistence.ModelSourceRootWalker</code>, and <code>jetbrains.mps.persistence.DefaultModelRoot</code>.
Here is an excerpt from an actual CI run:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="text">[ERROR]  [generate] 2026-05-28 12:12:14,498 WARNING - jetbrains.mps.persistence.ModelSourceRootWalker - Source root 'SourceRoot [/some/path/generator/templates]' does not exist, cannot traverse!

[ERROR]  [generate] 2026-05-28 12:12:14,499 WARNING - jetbrains.mps.persistence.DefaultModelRoot - Models have not been found within the SourceRoot [/some/path/generator/templates]</code></pre>
</div>
</div>
<div class="paragraph">
<p>These messages are not errors.
The build succeeds.
However, they appear in the Maven output prefixed with <code>[ERROR]</code>, which visually mixes them with actual build failures and makes real errors harder to locate.
On a large CI log, a dozen mislabelled warnings can hide a single genuine failure.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cause">Cause</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The messages are logged as <code>WARNING</code> by MPS via <code>java.util.logging</code>.
JUL&#8217;s default <code>ConsoleHandler</code> writes <code>WARNING</code> records to <code>System.err</code>.
Somewhere in the pipeline between stderr and the final Maven output, stderr content gets tagged as <code>[ERROR]</code>.
That is likely why a <code>WARNING</code> written to stderr shows up as an error in CI.</p>
</div>
<div class="paragraph">
<p>The tag depends on the stream, not on the JUL severity: bytes on stderr get <code>[ERROR]</code>, bytes on stdout get <code>[INFO]</code>.
Whatever assigns the tag looks at where the bytes came from, not at what they say.</p>
</div>
<div class="paragraph">
<p>Two intervention points are available: stop the message at the source (filter), or change the stream it uses (redirect).</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="solution-a-level-based-filter">Solution A: Level-based filter</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A JUL configuration file raises the log level of the affected loggers to <code>SEVERE</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="properties"><span class="py">jetbrains.mps.classloading.ModulesWatcher.level</span> <span class="p">=</span> <span class="s">SEVERE</span>
<span class="py">jetbrains.mps.persistence.ModelSourceRootWalker.level</span> <span class="p">=</span> <span class="s">SEVERE</span>
<span class="py">jetbrains.mps.persistence.DefaultModelRoot.level</span> <span class="p">=</span> <span class="s">SEVERE</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The configuration file is passed to the JVM via <code>-Djava.util.logging.config.file=/path/to/logging.properties</code>.
Once loaded, JUL drops all <code>WARNING</code> records from the listed loggers before they reach any handler.</p>
</div>
<div class="paragraph">
<p><strong>Consequences.</strong> The messages are gone from the log.
If one of these loggers later emits a new <code>WARNING</code> that would have been informative, it is dropped as well.
This solution treats output from the affected loggers as irrelevant noise.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="solution-b-stream-redirect-via-custom-handler">Solution B: Stream redirect via custom handler</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A custom JUL handler writes to <code>System.out</code> instead of <code>System.err</code>, while preserving <code>System.err</code> for <code>SEVERE</code> records:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kn">package</span> <span class="nn">example.logging</span><span class="o">;</span> <span class="c1">// replace with your own package</span>

<span class="kn">import</span> <span class="nn">java.util.logging.*</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">StdoutHandler</span> <span class="kd">extends</span> <span class="nc">StreamHandler</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="nf">StdoutHandler</span><span class="o">()</span> <span class="o">{</span>
        <span class="kd">super</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SimpleFormatter</span><span class="o">());</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kd">synchronized</span> <span class="kt">void</span> <span class="nf">publish</span><span class="o">(</span><span class="nc">LogRecord</span> <span class="n">record</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">if</span> <span class="o">(</span><span class="n">record</span><span class="o">.</span><span class="na">getLevel</span><span class="o">().</span><span class="na">intValue</span><span class="o">()</span> <span class="o">&gt;=</span> <span class="nc">Level</span><span class="o">.</span><span class="na">SEVERE</span><span class="o">.</span><span class="na">intValue</span><span class="o">())</span> <span class="o">{</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">err</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">getFormatter</span><span class="o">().</span><span class="na">format</span><span class="o">(</span><span class="n">record</span><span class="o">));</span>
            <span class="nc">System</span><span class="o">.</span><span class="na">err</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
            <span class="k">return</span><span class="o">;</span>
        <span class="o">}</span>
        <span class="kd">super</span><span class="o">.</span><span class="na">publish</span><span class="o">(</span><span class="n">record</span><span class="o">);</span>
        <span class="n">flush</span><span class="o">();</span>
    <span class="o">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kd">synchronized</span> <span class="kt">void</span> <span class="nf">close</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">flush</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>StreamHandler</code> buffers its output, so the explicit <code>flush()</code> after each <code>publish()</code> call is necessary;
without it, records may appear late or interleave unexpectedly with output from other handlers.</p>
</div>
<div class="paragraph">
<p>The JUL properties file routes the affected loggers through this handler and detaches them from the root handler chain:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="properties"><span class="py">handlers</span> <span class="p">=</span> <span class="s">java.util.logging.ConsoleHandler</span>
<span class="py">.level</span> <span class="p">=</span> <span class="s">WARNING</span>
<span class="py">java.util.logging.ConsoleHandler.level</span> <span class="p">=</span> <span class="s">WARNING</span>
<span class="py">java.util.logging.ConsoleHandler.formatter</span> <span class="p">=</span> <span class="s">java.util.logging.SimpleFormatter</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>handlers</code> registers <code>ConsoleHandler</code> on the root logger.
<code>.level</code> sets the root logger&#8217;s own level, which every logger in the tree without its own explicit level inherits
&#8201;&#8212;&#8201;including the three MPS loggers redirected below, which have no explicit level of their own.
<code>ConsoleHandler.level</code> sets the handler&#8217;s own, independent level.
A handler filters separately from the logger it&#8217;s attached to, regardless of which of the two is stricter.
And <code>ConsoleHandler.formatter</code> sets the formatter explicitly, matching <code>ConsoleHandler</code> own default.
These properties and their defaults are documented in the <code>ConsoleHandler</code> class documentation <sup class="footnote">[<a id="_footnoteref_2" class="footnote" href="#_footnotedef_2" title="View footnote.">2</a>]</sup>
and <sup class="footnote">[<a id="_footnoteref_3" class="footnote" href="#_footnotedef_3" title="View footnote.">3</a>]</sup>.</p>
</div>
<div class="paragraph">
<p>The JUL properties file also routes the affected loggers through this handler and detaches them from the root handler chain:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="properties"><span class="py">jetbrains.mps.classloading.ModulesWatcher.handlers</span> <span class="p">=</span> <span class="s">example.logging.StdoutHandler</span>
<span class="py">jetbrains.mps.classloading.ModulesWatcher.useParentHandlers</span> <span class="p">=</span> <span class="s">false</span>
<span class="py">jetbrains.mps.persistence.ModelSourceRootWalker.handlers</span> <span class="p">=</span> <span class="s">example.logging.StdoutHandler</span>
<span class="py">jetbrains.mps.persistence.ModelSourceRootWalker.useParentHandlers</span> <span class="p">=</span> <span class="s">false</span>
<span class="py">jetbrains.mps.persistence.DefaultModelRoot.handlers</span> <span class="p">=</span> <span class="s">example.logging.StdoutHandler</span>
<span class="py">jetbrains.mps.persistence.DefaultModelRoot.useParentHandlers</span> <span class="p">=</span> <span class="s">false</span>

<span class="py">example.logging.StdoutHandler.level</span> <span class="p">=</span> <span class="s">WARNING</span>
<span class="py">example.logging.StdoutHandler.formatter</span> <span class="p">=</span> <span class="s">java.util.logging.SimpleFormatter</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>useParentHandlers = false</code> line is required.
Without it, each record goes both to the custom handler and to the root <code>ConsoleHandler</code>, appearing twice: once on stdout, once on stderr.</p>
</div>
<div class="paragraph">
<p>The compiled handler must be available to the JVM early in startup, before the first log call.
In principle, adding the JAR to the regular classpath (<code>-cp</code>) would work, since JUL loads handler classes through the system classloader.
In this setup, however, we pass the logging configuration via <code>JAVA_TOOL_OPTIONS</code> (see below), which propagates to any downstream forked JVMs.
Placing the handler JAR on the bootclasspath guarantees availability regardless of the classpath configuration each fork ends up with:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="o">-</span><span class="nc">Xbootclasspath</span><span class="o">/</span><span class="nl">a:</span><span class="o">/</span><span class="n">path</span><span class="o">/</span><span class="n">to</span><span class="o">/</span><span class="n">logging</span><span class="o">-</span><span class="n">handler</span><span class="o">.</span><span class="na">jar</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Consequences.</strong> The <code>WARNING</code> records are kept visible in the log, but appear with an <code>[INFO]</code> prefix (because Maven tags stdout as <code>[INFO]</code>).
Real <code>SEVERE</code> records still route through <code>stderr</code> and appear as <code>[ERROR]</code>, preserving the ability to see genuine errors from the same loggers.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="trade-off">Trade-off</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The two solutions differ in what happens to future, unexpected messages from the affected loggers.</p>
</div>
<div class="paragraph">
<p>Solution A minimises the moving parts.
It is one properties file.
It fits situations where the loggers are known to produce only irrelevant noise, and preserving that assumption is acceptable.</p>
</div>
<div class="paragraph">
<p>Solution B costs a Java class, a compile step, and a bootclasspath entry.
It fits situations where the loggers may occasionally produce information worth seeing, and only the <code>[ERROR]</code> labelling is the problem, not the content.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="consequence-jvm-argument-propagation">Consequence: JVM argument propagation</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The JVM arguments described above (<code>-Xbootclasspath/a:&#8230;&#8203;</code> and <code>-Djava.util.logging.config.file=&#8230;&#8203;</code>) can be passed via either <code>MAVEN_OPTS</code> or <code>JAVA_TOOL_OPTIONS</code>.
The two behave differently:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>MAVEN_OPTS</code> is a shell variable read by the <code>mvn</code> script. It is applied to the initial Maven JVM only.
It is not propagated to forked JVMs <sup class="footnote">[<a id="_footnoteref_4" class="footnote" href="#_footnotedef_4" title="View footnote.">4</a>]</sup>.</p>
</li>
<li>
<p><code>JAVA_TOOL_OPTIONS</code> is a real environment variable defined by the JVM Tool Interface specification <sup class="footnote">[<a id="_footnoteref_5" class="footnote" href="#_footnotedef_5" title="View footnote.">5</a>]</sup>.
Every JVM started in the process tree reads and applies it, including forked children <sup class="footnote">[<a id="_footnoteref_6" class="footnote" href="#_footnotedef_6" title="View footnote.">6</a>]</sup>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If the build has any forked JVMs downstream of Maven (test runners, generator tasks, RCP builds), those forks need the same logging configuration.
In that case, <code>JAVA_TOOL_OPTIONS</code> is required.
<code>MAVEN_OPTS</code> alone leaves the forked JVMs on their default JUL configuration, and the warnings reappear from those processes.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="consequence-the-picked-up-java_tool_options-message">Consequence: the <code>Picked up JAVA_TOOL_OPTIONS</code> message</h2>
<div class="sectionbody">
<div class="paragraph">
<p>When <code>JAVA_TOOL_OPTIONS</code> is set, the JVM emits a startup notification:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="o">[</span><span class="no">ERROR</span><span class="o">]</span> <span class="nc">Picked</span> <span class="n">up</span> <span class="nl">JAVA_TOOL_OPTIONS:</span> <span class="o">-</span><span class="nc">Xbootclasspath</span><span class="o">/</span><span class="nl">a:</span><span class="o">...</span> <span class="o">-</span><span class="nc">Djava</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">logging</span><span class="o">.</span><span class="na">config</span><span class="o">.</span><span class="na">file</span><span class="o">=...</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This message is emitted by HotSpot itself, written to <code>stderr</code> at every JVM start, and consequently appears as <code>[ERROR]</code> in the CI log.
It is not an actual error.</p>
</div>
<div class="paragraph">
<p>The message cannot be disabled through JVM flags.
An OpenJDK bug requesting a suppression option was filed in 2014 and closed with resolution <code>Won&#8217;t Fix</code> <sup class="footnote">[<a id="_footnoteref_7" class="footnote" href="#_footnotedef_7" title="View footnote.">7</a>]</sup>.
The rationale given in the bug comments is brief: <em>"This will not be implemented, as it may introduce a vulnerability."</em></p>
</div>
<div class="paragraph">
<p>Practical option: accept the single cosmetic line per JVM start and document it.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="consequence-the-two-line-log-format">Consequence: the two-line log format</h2>
<div class="sectionbody">
<div class="paragraph">
<p>After the redirect, <code>SimpleFormatter</code> writes each log entry across two lines by default.
In the CI log, each line receives its own <code>[INFO]</code> prefix,
and the first line ends with the method name of the log call (<code>warning</code>), which visually resembles a severity tag and can be mistaken for a duplicate:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="text">[INFO]  [generate] Jun 16, 2026 8:13:09 AM jetbrains.mps.logging.JULogger warning
[INFO]  [generate] WARNING: 2 modules are marked as invalid roots for class loading out of 815 modules totally in the CL graph</code></pre>
</div>
</div>
<div class="paragraph">
<p>The fix is a format string in the JUL properties file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="properties"><span class="py">java.util.logging.SimpleFormatter.format</span> <span class="p">=</span> <span class="s">%1$tF %1$tT %4$s %3$s - %5$s%6$s%n</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The format tokens are documented in the <code>java.util.logging.SimpleFormatter</code> API <sup class="footnote">[<a id="_footnoteref_8" class="footnote" href="#_footnotedef_8" title="View footnote.">8</a>]</sup>.
<code>%1$tF %1$tT</code> is ISO date and time, <code>%4$s</code> is the level, <code>%3$s</code> is the logger name,
<code>%5$s</code> is the message, <code>%6$s</code> is the stack trace if present, and <code>%n</code> is one newline.
The same log entry now appears as a single line:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="text">[INFO]  [generate] 2026-06-16 09:05:53 WARNING jetbrains.mps.classloading.ModulesWatcher - 2 modules are marked as invalid roots for class loading out of 815 modules totally in the CL graph</code></pre>
</div>
</div>
<div class="paragraph">
<p>One entry per line, one prefix per line.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="result">Result</h2>
<div class="sectionbody">
<div class="paragraph">
<p>With Solution B in place, the CI log shows the affected warnings prefixed as <code>[INFO]</code> instead of <code>[ERROR]</code>.
Real <code>SEVERE</code> events from the same loggers continue to appear as <code>[ERROR]</code>.
The build itself is unchanged; only the log presentation is corrected.</p>
</div>
</div>
</div>
<div id="footnotes">
<hr>
<div class="footnote" id="_footnotedef_1">
<a href="#_footnoteref_1">1</a>. Java Util Logging (JUL): The Complete Guide to Built-in Java Logging, <a href="https://www.dash0.com/faq/java-util-logging-jul-the-complete-guide-to-built-in-java-logging" class="bare">https://www.dash0.com/faq/java-util-logging-jul-the-complete-guide-to-built-in-java-logging</a>
</div>
<div class="footnote" id="_footnotedef_2">
<a href="#_footnoteref_2">2</a>. Class ConsoleHandler, <a href="https://docs.oracle.com/en/java/javase/12/docs/api/java.logging/java/util/logging/ConsoleHandler.html" class="bare">https://docs.oracle.com/en/java/javase/12/docs/api/java.logging/java/util/logging/ConsoleHandler.html</a>
</div>
<div class="footnote" id="_footnotedef_3">
<a href="#_footnoteref_3">3</a>. Java Log Levels: How to Use Them in Practice, Dash0, <a href="https://www.dash0.com/knowledge/java-log-levels" class="bare">https://www.dash0.com/knowledge/java-log-levels</a>
</div>
<div class="footnote" id="_footnotedef_4">
<a href="#_footnoteref_4">4</a>. SUREFIRE-1035: When forking a JVM, JVM settings are not inherited from MAVEN_OPTS., <a href="https://issues.apache.org/jira/browse/SUREFIRE-1035" class="bare">https://issues.apache.org/jira/browse/SUREFIRE-1035</a>
</div>
<div class="footnote" id="_footnotedef_5">
<a href="#_footnoteref_5">5</a>. JVM Tool Interface Specification, <a href="https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html" class="bare">https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html</a>
</div>
<div class="footnote" id="_footnotedef_6">
<a href="#_footnoteref_6">6</a>. Oracle JVM Troubleshooting Guide on environment variables, <a href="https://docs.oracle.com/en/java/javase/11/troubleshoot/environment-variables-and-system-properties.html" class="bare">https://docs.oracle.com/en/java/javase/11/troubleshoot/environment-variables-and-system-properties.html</a>
</div>
<div class="footnote" id="_footnotedef_7">
<a href="#_footnoteref_7">7</a>. JDK-8039152, "Need a way to suppress message when picking up JAVA_TOOL_OPTIONS", <a href="https://bugs.openjdk.org/browse/JDK-8039152" class="bare">https://bugs.openjdk.org/browse/JDK-8039152</a>
</div>
<div class="footnote" id="_footnotedef_8">
<a href="#_footnoteref_8">8</a>. <code>java.util.logging.SimpleFormatter</code> API documentation, <a href="https://docs.oracle.com/javase/8/docs/api/java/util/logging/SimpleFormatter.html" class="bare">https://docs.oracle.com/javase/8/docs/api/java/util/logging/SimpleFormatter.html</a>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="Java" /><category term="Maven" /><category term="JetBrains MPS" /><category term="Logging" /><summary type="html"><![CDATA[In a Maven+Ant build using MPS, harmless JUL warnings appear as [ERROR] entries in the CI log. This post describes the cause and two possible fixes with their trade-offs.]]></summary></entry><entry><title type="html">Caching MPS Build Output in GitHub Actions</title><link href="https://www.f1re.io/2026-06-05/github-actions-mps-cache" rel="alternate" type="text/html" title="Caching MPS Build Output in GitHub Actions" /><published>2026-06-05T00:00:00+00:00</published><updated>2026-06-05T00:00:00+00:00</updated><id>https://www.f1re.io/2026-06-05/github-actions-mps-cache</id><content type="html" xml:base="https://www.f1re.io/2026-06-05/github-actions-mps-cache"><![CDATA[<div id="toc" class="toc">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#rationale">Rationale</a></li>
<li><a href="#the-problem">The Problem</a></li>
<li><a href="#the-approach">The Approach</a>
<ul class="sectlevel2">
<li><a href="#splitting-save-and-restore">Splitting Save and Restore</a></li>
<li><a href="#tarring-the-generated-output">Tarring the Generated Output</a></li>
<li><a href="#cache-keys-and-branch-scoping">Cache Keys and Branch Scoping</a></li>
<li><a href="#compression-choice">Compression Choice</a></li>
<li><a href="#putting-it-all-together">Putting It All Together</a></li>
<li><a href="#enable-mps-skip-unmodified-models-property">Enable MPS skip unmodified models property</a></li>
</ul>
</li>
<li><a href="#implementation-checklist">Implementation Checklist</a></li>
<li><a href="#pitfalls-and-gotchas">Pitfalls and Gotchas</a>
<ul class="sectlevel2">
<li><a href="#argument-list-too-long">Argument List Too Long</a></li>
<li><a href="#cache-immutability">Cache Immutability</a></li>
<li><a href="#path-mismatches-between-save-and-restore">Path Mismatches Between Save and Restore</a></li>
<li><a href="#github-actions-total-cache-storage">GitHub Actions total cache storage</a></li>
<li><a href="#stale-caches-breaking-the-build">Stale Caches Breaking the Build</a></li>
<li><a href="#random-build-failures">Random build failures</a></li>
</ul>
</li>
<li><a href="#results">Results</a></li>
<li><a href="#closing-thoughts">Closing Thoughts</a></li>
</ul>
</div>
<div class="sect1">
<h2 id="rationale">Rationale</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It&#8217;s 16:30 on a slow Wednesday, you&#8217;re finishing up your pull request for the day.
You get a comment, requesting to change the name of a variable so it&#8217;s easier to understand.
Sure, your commit takes 10 seconds to finalize.
And now you have to wait 30 minutes for the build, staring through the window and waving the colleagues goodbye one by one.</p>
</div>
<div class="paragraph">
<p>GitHub Actions has a caching mechanism and MPS generated output is exactly the kind of "expensive to produce, cheap to store" artifact that benefits from caching.</p>
</div>
<div class="paragraph">
<p>A match made in heaven.</p>
</div>
<div class="paragraph">
<p>This post is a checklist for setting it up and a summary of the gotchas we hit along the way.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-problem">The Problem</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The project is the domain experts side, so it has no language modules, just solutions.
It uses Maven, it has tens of solutions with hundreds of models.
Lots of people work on separate branches, this means <strong>a lot</strong> of repeat building of mostly the same things.</p>
</div>
<div class="paragraph">
<p>On every push, we start a fresh runner, it pulls the dependencies, starts MPS and starts chugging through generators.
This happens on a 1 line change, and on a 100 lines change.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-approach">The Approach</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Persist the generated output between runs and only regenerate what has actually changed.</p>
</div>
<div class="paragraph">
<p>GitHub Actions provides <code>actions/cache</code> for storing files in the GitHub Cache.
However, as is with everything MPS, it&#8217;s not that simple.
MPS generated output directories (<code>source_gen</code>, <code>classes_gen</code>, <code>source_gen.caches</code>, <code>test_gen</code> and <code>test_gen.caches</code>) sit in the same folder as the module file and model directories.
So we have to pick which directories will be saved.</p>
</div>
<div class="paragraph">
<p>To solve this, we ended up with two composite actions:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>restore-mps-cache</code> — runs before the build, restores cached generated output.</p>
</li>
<li>
<p><code>save-mps-cache</code> — runs after the build, saves the new generated output if it&#8217;s new.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Both are called from inside our <code>build-mps</code> composite action, so the caching logic stays out of the main pipeline file.</p>
</div>
<div class="sect2">
<h3 id="splitting-save-and-restore">Splitting Save and Restore</h3>
<div class="paragraph">
<p>The standard GitHub action <code>actions/cache@v5</code> handles both restore and save in a single step, but it gives us less control.</p>
</div>
<div class="paragraph">
<p>So we decided to re-use its components, <a href="https://github.com/actions/cache/tree/main/restore">actions/cache/restore</a> and <a href="https://github.com/actions/cache/tree/main/save">actions/cache/save</a>, separately.
That way we can skip the save when the restore was a full cache hit (no point re-saving identical content).</p>
</div>
<div class="paragraph">
<p>Cache files are branch specific so if we save identical cache files in separate branches they will consume extra space on the disk.
We tried to handle this as much as possible using restore keys, because our project is storage hungry.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">name</span><span class="pi">:</span> <span class="s">restore-mps-cache</span>
<span class="na">description</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">Restores MPS generated output [source_gen(.caches), classes_gen, test_gen(.caches)] under {your-mps-project-base-path}/.</span>

<span class="na">inputs</span><span class="pi">:</span>
  <span class="na">mps-cache-key</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Cache key for MPS generated output</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">mps-cache-restore-keys</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Fallback restore keys for MPS cache (newline-separated)</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">false</span>
    <span class="na">default</span><span class="pi">:</span> <span class="s1">'</span><span class="s">'</span>

<span class="na">outputs</span><span class="pi">:</span>
  <span class="na">mps-cache-hit</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Whether an MPS cache was restored</span>
    <span class="na">value</span><span class="pi">:</span> <span class="s">${{ steps.restore_mps.outputs.cache-matched-key != '' }}</span>

<span class="na">runs</span><span class="pi">:</span>
  <span class="na">using</span><span class="pi">:</span> <span class="s">composite</span>
  <span class="na">steps</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Restore MPS Generated Output</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">restore_mps</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache/restore@v5</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">path</span><span class="pi">:</span> <span class="s">${{ github.workspace }}/mps-gen-cache.tar.zst</span>
        <span class="na">key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">restore-keys</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-restore-keys }}</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Unpack MPS Generated Output</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">steps.restore_mps.outputs.cache-hit == 'true'</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">tar -x --zstd \</span>
        <span class="s">-f ${{ github.workspace }}/mps-gen-cache.tar.zst \</span>
        <span class="s">-C ${{ github.workspace }}</span></code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<code>actions/cache/restore@v5</code> has had reliability issues.
If you hit weird "cache not found" errors despite the entry visibly existing, this is a candidate for investigation.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="tarring-the-generated-output">Tarring the Generated Output</h3>
<div class="paragraph">
<p>The first wall we hit was an <code>Argument list too long</code> error from the cache action.
Our project produces around 350 individual <code>_gen</code> directories, and passing all of them as a list of paths to the cache action exceeded the OS argument limit.</p>
</div>
<div class="paragraph">
<p>The fix is to tar everything into a single archive before saving and untar it on restore.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">name</span><span class="pi">:</span> <span class="s">save-mps-cache</span>
<span class="na">description</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">Saves MPS generated output [source_gen(.caches), classes_gen, test_gen(.caches)] under {your-mps-project-base-path}/.</span>

<span class="na">inputs</span><span class="pi">:</span>
  <span class="na">mps-cache-key</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Cache key for MPS generated output</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">mps-cache-hit</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Whether a full cache hit occurred during restore. Skips save if </span><span class="no">true</span><span class="s">.</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">false</span>
    <span class="na">default</span><span class="pi">:</span> <span class="s1">'</span><span class="s">false'</span>

<span class="na">runs</span><span class="pi">:</span>
  <span class="na">using</span><span class="pi">:</span> <span class="s">composite</span>
  <span class="na">steps</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Archive MPS Generated Output</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">inputs.mps-cache-hit != 'true'</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">find ${{ github.workspace }}/{your-mps-project-base-path} \</span>
        <span class="s">-mindepth 2 -maxdepth 2 -type d \( -name 'source_gen' -o -name 'classes_gen' -o -name 'source_gen.caches' -o -name 'test_gen' -o -name 'test_gen.caches' \) \</span>
        <span class="s">-print0 | sed -z "s|${{ github.workspace }}/||" | \</span>
        <span class="s">tar -c -I"zstd -19 -T0" \</span>
        <span class="s">-f ${{ github.workspace }}/mps-gen-cache.tar.zst \</span>
        <span class="s">-C ${{ github.workspace }} \</span>
        <span class="s">--null --files-from=-</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Save MPS Generated Output</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">inputs.mps-cache-hit != 'true'</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">actions/cache/save@v5</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">path</span><span class="pi">:</span> <span class="s">${{ github.workspace }}/mps-gen-cache.tar.zst</span>
        <span class="na">key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The archiving step is quite big, so I&#8217;ll explain everything:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>find</code> uses <code>-mindepth 2 -maxdepth 2</code> to target only the top-level gen directories under each solution, not their contents.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you are going to implement this on a project with languages and generators, you have to also include the generator folders, which are usually inside {mps-language}/{generator}/*_gen, so the find command has to be extended for deeper searching.
This might look like just extending the -maxdepth property to 4 but if your project is big, it might need more thought.
</td>
</tr>
</table>
</div>
<div class="ulist">
<ul>
<li>
<p><code>-type d \( -name 'source_gen' -o -name 'classes_gen' -o -name 'source_gen.caches' -o -name 'test_gen' -o -name 'test_gen.caches' \)</code> specifies we are looking for directories with these names, I decided to specify them explicitly so we don&#8217;t catch anything else by accident.</p>
</li>
<li>
<p><code>-print0</code> makes <code>find</code> delimit its output with null bytes (<code>\0</code>) instead of newlines.
The default newline delimiter breaks if any of the paths contain whitespaces.</p>
</li>
<li>
<p><code>sed -z "s|${{ github.workspace }}/||"</code> substitutes everything up to and including <code>${{ github.workspace }}/</code> so we work in the path relative to the workspace root.
<code>-z</code> makes <code>sed</code> treat null bytes as record separators.</p>
</li>
<li>
<p><code>tar -c -I"zstd -19 -T0"</code>: <code>-c</code> creates a new archive using the <code>zstd</code> compressor at <code>-19</code> compression level and <code>-T0</code> to use all available CPU cores.</p>
</li>
</ul>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Make sure the same compression flag is used on both ends. Mixing (de)compression algorithms will give you a fun afternoon.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="cache-keys-and-branch-scoping">Cache Keys and Branch Scoping</h3>
<div class="paragraph">
<p>GitHub caches are scoped per branch by default.
A cache saved on <code>feature-a</code> is not visible from <code>feature-b</code>.
Caches saved on the default branch are restorable from all branches.</p>
</div>
<div class="paragraph">
<p>We use a key that includes the runner OS, branch name, language version and a hash of the <strong>build</strong> model files:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ runner.os }}-mps-cache-${{ github.ref_name }}-${{ steps.prepare_job.outputs.language-version }}-${{ hashFiles('{your-mps-project-base-path}/build-solutions/**/models/*.mps') }}</span>
<span class="na">mps-cache-restore-keys</span><span class="pi">:</span> <span class="s">${{ runner.os }}-mps-cache-main-${{ steps.prepare_job.outputs.language-version }}-${{ hashFiles('{your-mps-project-base-path}/build-solutions/**/models/*.mps') }}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We use the build models so we can capture caches using the dependencies of the project modules.
The hash ensures we only ever restore a cache that matches the current version and set of dependencies.
This decreases the chance of us using stale caches and breaking our builds, but also ensures we get hits and not have different hashes on every change.</p>
</div>
<div class="paragraph">
<p>The <code>mps-cache-restore-keys</code> provides a fallback to the most recent cache from <code>main</code> when a branch has no cache of its own yet.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
If you scope by branch only and not by content hash, there is a greater chance that a stale cache <strong>will</strong> break your build the moment a model is changed.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="compression-choice">Compression Choice</h3>
<div class="paragraph">
<p>Our first version used xz (<code>-cJf</code>), but we found a better option.</p>
</div>
<div class="paragraph">
<p>After comparing other algorithms, I found that <code>zstd -19</code> wins for our case.
It achieved near-identical size to xz, while compressing much faster, and size is the deciding factor when we are trying to fit 50 cache items in 10GB.</p>
</div>
<table id="compression-comparison" class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Algorithm</th>
<th class="tableblock halign-left valign-top">Compress</th>
<th class="tableblock halign-left valign-top">Decompress</th>
<th class="tableblock halign-left valign-top">Size</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">xz</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">9m51s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">25s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">99MB</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">gzip</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">42s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">16s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">198MB</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">zstd (default)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">6s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">11s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">171MB</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">zstd -19</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">6m36s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">13s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">95MB</p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
zstd should be available on GitHub-hosted Ubuntu runners by default.
Verify on your specific runner image before relying on it.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="putting-it-all-together">Putting It All Together</h3>
<div class="paragraph">
<p>Here is what the full caching flow looks like inside a composite action:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">name</span><span class="pi">:</span> <span class="s">run-mps-build</span>

<span class="na">inputs</span><span class="pi">:</span>
  <span class="na">use-mps-cache</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Use cache when rebuilding MPS sources for quicker pipeline runs</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">mps-cache-key</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Cache key for MPS generated output</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">mps-cache-restore-keys</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Fallback restore keys for MPS cache (newline-separated)</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">false</span>
    <span class="na">default</span><span class="pi">:</span> <span class="s1">'</span><span class="s">'</span>

<span class="na">runs</span><span class="pi">:</span>
  <span class="na">using</span><span class="pi">:</span> <span class="s">composite</span>
  <span class="na">steps</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Restore MPS cache</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">inputs.use-mps-cache == 'true'</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">restore_mps</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/actions/restore-mps-cache</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">mps-cache-restore-keys</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-restore-keys }}</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run MPS build</span>
      <span class="c1"># ... your build steps here ...</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Save MPS cache</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">save_mps</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/actions/save-mps-cache</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">mps-cache-hit</span><span class="pi">:</span> <span class="s">${{ steps.restore_mps.outputs.mps-cache-hit }}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The project is split into DSL MPS project and the user models MPS project.
On the user models project which depended on the DSL project we added another check to both cache steps: <code>is-snapshot</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml">    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Restore MPS cache</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">inputs.use-mps-cache == 'true' &amp;&amp; inputs.is-snapshot != 'true'</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">restore_mps</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/actions/restore-mps-cache</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">mps-cache-restore-keys</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-restore-keys }}</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run MPS build</span>
      <span class="c1"># ... your build steps here ...</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Save MPS cache</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">inputs.is-snapshot != 'true'</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">save_mps</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/actions/save-mps-cache</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">mps-cache-hit</span><span class="pi">:</span> <span class="s">${{ steps.restore_mps.outputs.mps-cache-hit }}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We decided to not use cache if our language version was a SNAPSHOT, because the developer team used SNAPSHOTs for quick patches and testing.
Using the cache for such versions increased the chances of using stale code and masking the changes a developer was trying to test, so we decided to not run it at all.</p>
</div>
</div>
<div class="sect2">
<h3 id="enable-mps-skip-unmodified-models-property">Enable MPS skip unmodified models property</h3>
<div class="paragraph">
<p>This is the backbone of the entire operation.</p>
</div>
<div class="paragraph">
<p>None of this would matter if MPS just regenerates everything over the cache files anyway.
We have to tell it via the build script to skip unmodified models.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/github-actions-mps-cache/generator-options.PNG" alt="generator options">
</div>
<div class="title">Figure 1. Build script property</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="implementation-checklist">Implementation Checklist</h2>
<div class="sectionbody">
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><i class="fa fa-square-o"></i> Find the "Build MPS" action in your pipeline.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Define <code>mps-cache-key</code> input.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Optionally define <code>mps-cache-restore-keys</code> to fall back to the most recent visible cache.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Write <code>restore-mps-cache</code> GitHub action yml file.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Write <code>save-mps-cache</code> GitHub action yml file.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Call the <code>restore-mps-cache</code> action before the build step.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Call the <code>save-mps-cache</code> action after the build step.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Verify the cache was saved under Actions → Caches in the GitHub UI.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Add conditional input <code>use-mps-cache</code> for explicit control over cache usage.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Add conditional input <code>is-snapshot</code> for user model projects for extra checks during debugging.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Enable <code>skip unmodified models</code> generator option in your MPS build script.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="pitfalls-and-gotchas">Pitfalls and Gotchas</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="argument-list-too-long">Argument List Too Long</h3>
<div class="paragraph">
<p>If the cache action complains about argument length, you&#8217;re trying to cache too many individual paths.
Tar them into one file.</p>
</div>
</div>
<div class="sect2">
<h3 id="cache-immutability">Cache Immutability</h3>
<div class="paragraph">
<p>GitHub does not let you overwrite an existing cache key.
Same key means same content, by design.
If you want to "update" a cache, you have two options:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Append a unique element to the key</strong> (run ID, commit SHA) and use <code>restore-keys</code> for prefix matching to grab the most recent.
New entry every run.</p>
</li>
<li>
<p><strong>Delete the existing entry before saving.</strong> Useful when you want exactly one entry per branch to keep storage bounded.</p>
</li>
</ol>
</div>
</div>
<div class="sect2">
<h3 id="path-mismatches-between-save-and-restore">Path Mismatches Between Save and Restore</h3>
<div class="paragraph">
<p>Make sure your save and restore actions use the same properties, glob patterns and paths.
Mismatches here will silently produce a cache that "exists" and still build everything from scratch since it&#8217;s put somewhere else.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Add a debug step that prints the exact paths being cached and the exact paths being looked up.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="github-actions-total-cache-storage">GitHub Actions total cache storage</h3>
<div class="paragraph">
<p>GitHub Action&#8217;s default cache storage limit is 10GB.
This is not a lot considering the ~50 branches that people are working on.
Each branch would potentially have its own cache, so we have to use maximum compression, even if it makes it significantly slower (see <a href="#compression-comparison">[compression-comparison]</a>).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Entries not used for 7 days are deleted, long-lived feature branches may have to re-save their cache occasionally.
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="stale-caches-breaking-the-build">Stale Caches Breaking the Build</h3>
<div class="paragraph">
<p>The cache key must include a hash of the actual model files, not just the branch name.
A branch-only key will happily restore yesterday&#8217;s <code>source_gen</code> over today&#8217;s models, and MPS will either fail or produce wrong output.
The hash is what makes the cache safer.</p>
</div>
</div>
<div class="sect2">
<h3 id="random-build-failures">Random build failures</h3>
<div class="paragraph">
<p>We occasionally got build failures that seemed random and were resolved once we re-ran the build without cache.
This was happening on MPS 2025.1.1, the problem was found to be a transitive dependency bug that was being resolved by one of the other teams.</p>
</div>
<div class="paragraph">
<p>In the meantime I came up with a retry step that could alleviate the users' failing builds without them having to re-run them manually.
The solution is a Band-Aid so be careful when using it, but it worked for us.</p>
</div>
<div class="listingblock">
<div class="title">composite action</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml">    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run mvn build</span>
      <span class="na">continue-on-error</span><span class="pi">:</span> <span class="no">true</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">mvn_build</span>
      <span class="c1"># ... your build steps here ...</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Retry without cache</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">retry</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">steps.mvn_build.outcome == 'failure' &amp;&amp; steps.restore_mps.outputs.mps-cache-hit == 'true'</span>
      <span class="na">uses</span><span class="pi">:</span> <span class="s">./.github/actions/retry-mvn-build-without-cache</span>
      <span class="na">with</span><span class="pi">:</span>
        <span class="na">phase</span><span class="pi">:</span> <span class="s">${{ inputs.phase }}</span>
        <span class="na">mps-cache-key</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Surface build failure</span>
      <span class="na">if</span><span class="pi">:</span> <span class="s">steps.mvn_build.outcome == 'failure' &amp;&amp; steps.restore_mps.outputs.mps-cache-hit != 'true'</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">echo "Build failed and no cache was used — this is a genuine build failure."</span>
        <span class="s">exit 1</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>A word on how the failure handling works, because it&#8217;s easy to break.</p>
</div>
<div class="paragraph">
<p>The <code>mvn build</code> step uses <code>continue-on-error: true</code>.
This is deliberate: it stops a failed build from immediately failing the job, so we get a chance to retry without the cache.
The downside is that the build step alone can never fail the job anymore, so we need the two steps that follow it to decide the actual outcome.</p>
</div>
<div class="paragraph">
<p>There are three cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Build succeeds</strong> — neither follow-up step runs, the job passes.</p>
</li>
<li>
<p><strong>Build fails with a cache hit</strong> — the retry step runs, deletes the poisoned cache, wipes the generated output, and rebuilds from a clean state.
The retry&#8217;s own success or failure becomes the job&#8217;s result.</p>
</li>
<li>
<p><strong>Build fails without a cache hit</strong> — there&#8217;s nothing to blame the cache for, so this is a genuine failure.
The "Surface build failure" step runs <code>exit 1</code> to fail the job, since the build step no longer can.</p>
</li>
</ul>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
If you remove <code>continue-on-error: true</code>, the build will fail the job before the retry ever gets a chance to run, defeating the whole point.
And if you add it without the "Surface build failure" step, genuine failures will pass silently.
The three pieces only work together.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The condition on the surface step (<code>mps-cache-hit != 'true'</code>) also catches the case where caching is disabled and the step correctly fails the cache-less job.
So a real failure is always surfaced whether the cache was in play.</p>
</div>
<div class="sect3">
<h4 id="retry-build-without-cache-action">retry build without cache action</h4>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">name</span><span class="pi">:</span> <span class="s">retry-mvn-build-without-cache</span>
<span class="na">description</span><span class="pi">:</span> <span class="pi">&gt;-</span>
  <span class="s">Recovers from a failed mvn build that used the MPS cache. Deletes the</span>
  <span class="s">poisoned cache entry, wipes MPS generated output, and retries the build</span>
  <span class="s">from a clean state. Fails if the retry also fails.</span>

<span class="na">inputs</span><span class="pi">:</span>
  <span class="na">phase</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">mvn goals to execute</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">mps-cache-key</span><span class="pi">:</span>
    <span class="na">description</span><span class="pi">:</span> <span class="s">Cache key of the poisoned entry to delete</span>
    <span class="na">required</span><span class="pi">:</span> <span class="no">true</span>

<span class="na">runs</span><span class="pi">:</span>
  <span class="na">using</span><span class="pi">:</span> <span class="s">composite</span>
  <span class="na">steps</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Annotate cache-poisoning recovery</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="s">echo "::warning title=MPS cache poisoning detected::Build failed on first attempt with cache key '${{ inputs.mps-cache-key }}'. Retrying without cache."</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Delete poisoned cache entry</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">env</span><span class="pi">:</span>
        <span class="na">GH_TOKEN</span><span class="pi">:</span> <span class="s">${{ github.token }}</span>
        <span class="na">CACHE_KEY</span><span class="pi">:</span> <span class="s">${{ inputs.mps-cache-key }}</span>
        <span class="na">REPO</span><span class="pi">:</span> <span class="s">${{ github.repository }}</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">echo "Build failed with cache hit. Deleting cache entry: ${CACHE_KEY}"</span>
        <span class="s">gh cache delete "${CACHE_KEY}" --repo "${REPO}" \</span>
          <span class="s">|| echo "Cache delete failed (entry may already be gone); continuing."</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Wipe MPS generated output</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">echo "Removing MPS generated directories before retry."</span>
        <span class="s">find ${{ github.workspace }}/{your-mps-project-base-path} \</span>
          <span class="s">-mindepth 2 -maxdepth 2 -type d \</span>
          <span class="s">\( -name 'source_gen' -o -name 'classes_gen' -o -name 'source_gen.caches' -o -name 'test_gen' -o -name 'test_gen.caches' \) \</span>
          <span class="s">-exec rm -rf {} +</span>

    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Retry mvn clean + build without cache</span>
      <span class="na">id</span><span class="pi">:</span> <span class="s">mvn_retry</span>
      <span class="na">shell</span><span class="pi">:</span> <span class="s">bash</span>
      <span class="na">run</span><span class="pi">:</span> <span class="pi">|</span>
        <span class="s">mvn -B clean compile  # replace with your build goals; keep `clean`</span></code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="results">Results</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In optimal conditions — meaning a full cache hit on a branch with no model changes — the Build Phase dropped from <strong>15 minutes to 5 minutes</strong>.
Roughly a third of the original time, with most of what remained being the actual Java compilation and packaging.</p>
</div>
<div class="paragraph">
<p>Cache hits scale with how stable your models are between runs.
Branches with lots of model changes will see less benefit because they invalidate the cache more often.
But for the typical case of "domain expert changes a few models, the rest are untouched," the speedup is substantial.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="closing-thoughts">Closing Thoughts</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Most of the difficulty here came not from the caching itself but from the layers of abstractions we had to peel back: composite actions inside composite actions, MPS generating output in 350 places, GitHub&#8217;s branch scoping, immutability rules, and the cache action&#8217;s quirks around path handling.
Once each of those is understood, the actual code is fairly small.</p>
</div>
<div class="paragraph">
<p>If you find yourself optimising MPS pipelines and want to share something we missed, I&#8217;d love to hear about it, you can find my email below.</p>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="JetBrains MPS" /><category term="GitHub" /><summary type="html"><![CDATA[This post will follow a checklist for caching MPS generated output in GitHub Actions, and a summary of the gotchas we hit along the way.]]></summary></entry><entry><title type="html">Good method names</title><link href="https://www.f1re.io/2025-11-21/good-method-names" rel="alternate" type="text/html" title="Good method names" /><published>2025-11-21T00:00:00+00:00</published><updated>2025-11-21T00:00:00+00:00</updated><id>https://www.f1re.io/2025-11-21/good-method-names</id><content type="html" xml:base="https://www.f1re.io/2025-11-21/good-method-names"><![CDATA[<div class="paragraph">
<p>Everybody wants well-named methods&#8201;&#8212;&#8201;but what does that mean? We discuss the purpose of method names, guidelines for choosing them, and look at good and bad examples.</p>
</div>
<div class="sect1">
<h2 id="what-are-names-for">What are names for?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Method names tell code <em>readers</em> <strong>what</strong> the method does in its context.
Context consists of both the elements in the method&#8217;s surroundings, and their level of abstraction.</p>
</div>
<div class="paragraph">
<p>Secondary, names make methods <strong>discoverable</strong> while <em>writing</em> more code.</p>
</div>
<div class="paragraph">
<p>It&#8217;s way more important to cater to <em>readers</em> than <em>writers</em>, because we write code once, but read it a lot more.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
While the examples in this post use Java, the guidelines apply to most object-oriented methods, and also other functions and operations.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="guidelines">Guidelines</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="follow-naming-conventions">Follow naming conventions</h3>
<div class="paragraph">
<p>Most teams and all programming languages have standard conventions for method names.
Examples include "start with a verb", "don&#8217;t use underscores", or "start with lowercase character".
Follow them.</p>
</div>
<div class="paragraph">
<p>If we don&#8217;t like them, <em>first</em> have a discussion about the criticisms, and adjust names <em>after</em> our team agreed.
It helps nobody to have method <code>A.getName()</code>, <code>B.Get_Name()</code> and <code>C.name()</code>.</p>
</div>
<div class="sect3">
<h4 id="exceptions">Exceptions</h4>
<div class="paragraph">
<div class="title">Unit tests (and other "shell" methods)</div>
<p>Some methods are only "shells" for other concepts, because the language requires it.
Prime example are unit tests:
In most languages, a unit test is a method (because that&#8217;s the only place we can write code).
It&#8217;s more important to describe <em>what</em> the unit test does than following naming conventions.
For example, <code>Comparer_emptyLists()</code> does not conform to Java conventions (doesn&#8217;t start with a verb, uses underscores).
But it clearly tells <em>what</em> this unit test is about: it tests the <code>Comparer</code> by feeding two empty lists.
The next method might be called <code>Comparer_leftListEmpty()</code>&#8201;&#8212;&#8201;signalling it&#8217;s also testing <code>Comparer</code>, but with different input data.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="dont-fear-long-names">Don&#8217;t fear long names</h3>
<div class="paragraph">
<p>Make the name as long as needed for good understanding.
The length of a name is not an issue for any modern tool.
The times when compilers only distinguished the first 32 characters of a name are long gone.
We can also look at more than 25x80 characters on our screen by now.</p>
</div>
<div class="paragraph">
<p>Of course, there are limits: <code>calculateInterestOfPositiveBalanceByCalendarYearDisregardingLeapYears()</code> might describe what we&#8217;re doing, but does not help the reader.
At the time we&#8217;ve deciphered each camel-cased word, we&#8217;ve already forgotten what the name started with.</p>
</div>
<div class="paragraph">
<p>Struggling to find a descriptive short name might indicate our method does too many things.
Consider splitting it up.</p>
</div>
<div class="paragraph">
<p>Nowadays nobody should type complete method names&#8201;&#8212;&#8201;that&#8217;s what we have code completion for.
If we have to type more than 5 characters to call a method, something is off:
To call <code>calculateGeometricMean()</code>, nobody should type more than <code>cGM</code>, <code>calcG</code>, <code>GeoM</code> or similar.
Either get a better editor / IDE, or declutter the codebase from redundant names.</p>
</div>
<div class="sect3">
<h4 id="exceptions-2">Exceptions</h4>
<div class="paragraph">
<div class="title">Established names</div>
<p>Some abbreviated names are more established than their spelled out counterpart.
Most developer would first search for <code>sqrt()</code> before even thinking about <code>squareRoot()</code>.</p>
</div>
<div class="paragraph">
<div class="title">Repetition</div>
<p>If a method is called very often in a section of code, longer names can clutter the section.
One example is a classical interpreter implementation:</p>
</div>
<div class="listingblock">
<div class="title">Java example with short repeated method name</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">int</span> <span class="nf">eval</span><span class="o">(</span><span class="nc">Node</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="nf">switch</span> <span class="o">(</span><span class="n">node</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">case</span> <span class="nc">Plus</span> <span class="n">p</span> <span class="o">-&gt;</span> <span class="n">eval</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">+</span> <span class="n">eval</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Minus</span> <span class="n">m</span> <span class="o">-&gt;</span> <span class="n">eval</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">-</span> <span class="n">eval</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Mul</span> <span class="n">m</span> <span class="o">-&gt;</span> <span class="n">eval</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">*</span> <span class="n">eval</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Div</span> <span class="n">d</span> <span class="o">-&gt;</span> <span class="n">eval</span><span class="o">(</span><span class="n">d</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">/</span> <span class="n">eval</span><span class="o">(</span><span class="n">d</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Num</span> <span class="n">n</span> <span class="o">-&gt;</span> <span class="nc">Interger</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">n</span><span class="o">.</span><span class="na">value</span><span class="o">);</span>
    <span class="o">};</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This is easier to read than using the complete method name <code>evaluateNode</code>:</p>
</div>
<div class="listingblock">
<div class="title">Java example with complete, long repeated method name</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">int</span> <span class="nf">evaluateNode</span><span class="o">(</span><span class="nc">Node</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="nf">switch</span> <span class="o">(</span><span class="n">node</span><span class="o">)</span> <span class="o">{</span>
        <span class="k">case</span> <span class="nc">Plus</span> <span class="n">p</span> <span class="o">-&gt;</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">+</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">p</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Minus</span> <span class="n">m</span> <span class="o">-&gt;</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">-</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Mul</span> <span class="n">m</span> <span class="o">-&gt;</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">*</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Div</span> <span class="n">d</span> <span class="o">-&gt;</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">d</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">/</span> <span class="n">evaluateNode</span><span class="o">(</span><span class="n">d</span><span class="o">.</span><span class="na">right</span><span class="o">);</span>
        <span class="k">case</span> <span class="nc">Num</span> <span class="n">n</span> <span class="o">-&gt;</span> <span class="nc">Interger</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">n</span><span class="o">.</span><span class="na">value</span><span class="o">);</span>
    <span class="o">};</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="dont-repeat-class-or-parameter-names">Don&#8217;t repeat class or parameter names</h3>
<div class="paragraph">
<p>A method appears in an outer scope (its class), and contains some scopes (parameter names and types).
The class also appears in its own outer scope (depending on your programming language: module, namespace, package, etc.).
Don&#8217;t repeat these names in the method name.</p>
</div>
<div class="paragraph">
<p>We usually know the context of the method, either because we&#8217;re inside the same class (<code>this.detach()</code>), or from the part before the dot: <code>mySearchWidget.detach()</code>.
<code>mySearchWidget.detachWidget()</code> does not provide more information to the reader, but clutters the code and makes it harder to read.</p>
</div>
<div class="paragraph">
<p>The same applies to parameter types: <code>myComparer.compare(leftNode, rightNode)</code> tells us just as much as <code>myComparer.compareNode(leftNode, rightNode)</code>.
Most probably, We&#8217;d write <code>myComparer.compare(left, right)</code>, because we know in this context we <em>always</em> deal with <code>Node</code>s.</p>
</div>
<div class="paragraph">
<p>If we change the name of the class or parameter, it&#8217;s easy to forget updating the method&#8217;s name.
A method <code>Tree.createTreeLeaf()</code> is understandable, but once we rename the class, <code>Hierarchy.createTreeLeaf()</code> is confusing.</p>
</div>
<div class="sect3">
<h4 id="repeat-exceptions">Exceptions</h4>
<div class="paragraph">
<div class="title">Naming conventions</div>
<p>Follow the naming conventions of our team or language.
Prime example are getters and setters: <code>getName(String name)</code> / <code>setName(String name)</code> implement Java&#8217;s naming convention for a <code>name</code> property on a class.</p>
</div>
<div class="paragraph">
<div class="title">Extension methods</div>
<p>Some languages allow to add extension methods to foreign types.
For example, we can add a <code>AppendNodeDescendants(Node source)</code> method to the built-in <code>List</code> type and call <code>myList.AppendNodeDescendants(myNode)</code>.
If we called the method <code>AppendDescendants()</code>, we might confuse users of <code>List</code> that don&#8217;t know about
<code>Node</code>s and what <em>descendants</em> mean.</p>
</div>
<div class="paragraph">
<div class="title">Encapsulation</div>
<p>Let&#8217;s say we have some complex logic to add all relevant parts to a list.
We encapsulate this logic in a class <code>PartsAdder</code> with one public method.
<code>add()</code> is a better name than <code>execute()</code> or <code>run()</code>, even though it repeats the class name:
The reader better understands what the method does.</p>
</div>
<div class="paragraph">
<div class="title">Overloading or untyped language</div>
<p>If our language doesn&#8217;t support overloading, we need to repeat the parameter type in the method name: <code>addObject(Object newElement)</code>, <code>addInt(int newElement)</code>.</p>
</div>
<div class="paragraph">
<p>The same applies if we&#8217;re using an untyped language.</p>
</div>
<div class="paragraph">
<div class="title">Disambiguation in same context</div>
<p>Let&#8217;s assume we need to display the location of networked computers on a geographical map.
Both the network library, and the mapping library call their basic element <code>Node</code>.
Then method names like <code>addNetworkNode(org.landiscover.network.Node node)</code> and <code>addMapNode(com.google.maps.Node node)</code> are easier to understand than two <code>add()</code> methods.</p>
</div>
<div class="paragraph">
<p>We can also overuse overloading: If we had hundreds of <code>eval()</code> methods with different parameter types, the compiler can figure out which one gets called in each case&#8201;&#8212;&#8201;but for human readers it&#8217;s very hard to follow the call.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="move-shared-prefixes-suffixes-to-separate-classes">Move shared prefixes / suffixes to separate classes</h3>
<div class="paragraph">
<p>If we had two sets of methods with common prefix or suffix, e.g.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">Calculator</span> <span class="o">{</span>
  <span class="n">sumDouble</span><span class="o">(</span><span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">double</span> <span class="n">b</span><span class="o">);</span>
  <span class="n">multiplyDouble</span><span class="o">(</span><span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">double</span> <span class="n">b</span><span class="o">);</span>

  <span class="c1">// vs.</span>

  <span class="n">sumInt</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">);</span>
  <span class="n">multiplyInt</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">);</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>we should try to move the methods to separate classes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">DoubleCalculator</span> <span class="o">{</span>
  <span class="n">sum</span><span class="o">(</span><span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">double</span> <span class="n">b</span><span class="o">);</span>
  <span class="n">multiply</span><span class="o">(</span><span class="kt">double</span> <span class="n">a</span><span class="o">,</span> <span class="kt">double</span> <span class="n">b</span><span class="o">);</span>
<span class="o">}</span>

<span class="kd">class</span> <span class="nc">IntCalculator</span> <span class="o">{</span>
  <span class="n">sum</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">);</span>
  <span class="n">multiply</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">);</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This especially applies to unit test classes:
If we had a <code>CalculatorTest</code> class containing</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>sumDouble_twoPositive()</code></p>
</li>
<li>
<p><code>sumDouble_twoNegative()</code></p>
</li>
<li>
<p><code>sumDouble_twoZero()</code></p>
</li>
<li>
<p><code>multiplyDouble_twoPositive()</code></p>
</li>
<li>
<p><code>multiplyDouble_twoNegative()</code></p>
</li>
<li>
<p><code>multiplyDouble_twoZero()</code></p>
</li>
<li>
<p><code>sumInt_twoPositive()</code></p>
</li>
<li>
<p><code>sumInt_twoNegative()</code></p>
</li>
<li>
<p><code>sumInt_twoZero()</code></p>
</li>
<li>
<p><code>multiplyInt_twoPositive()</code></p>
</li>
<li>
<p><code>multiplyInt_twoNegative()</code></p>
</li>
<li>
<p><code>multiplyInt_twoZero()</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>we&#8217;d better split the class up in <code>CalculatorDoubleTest</code> and <code>CalculatorIntTest</code>, or even <code>CalculatorDoubleSumTest</code>, <code>CalculatorDoubleMultiplyTest</code> etc.
The methods would be called <code>twoPositive()</code>, <code>twoNegative()</code>, and <code>twoZero()</code>.</p>
</div>
<div class="sect3">
<h4 id="exceptions-3">Exceptions</h4>
<div class="paragraph">
<div class="title">Required by program structure</div>
<p>If all the methods have to access a shared internal state (e.g. assume a "current value" field in the <code>Calculator</code> example above), we might need to compromise on good names.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="avoid-get-set-and-test-prefix">Avoid "get" / "set" and "test" prefix</h3>
<div class="paragraph">
<p>No other English words have more different meanings than <a href="https://www.merriam-webster.com/dictionary/set">set</a> and <a href="https://www.merriam-webster.com/dictionary/get">get</a>.
Thus, we <em>can</em> use them for almost anything, but we <em>should</em> use them for almost nothing:
They don&#8217;t tell the reader what we mean.
The English language has thousands of other verbs we can use.</p>
</div>
<table class="tableblock frame-all grid-all fit-content">
<caption class="title">Table 1. Examples to avoid "get" / "set"</caption>
<colgroup>
<col>
<col>
</colgroup>
<tbody>
<tr>
<th class="tableblock halign-left valign-top"><p class="tableblock">Use</p></th>
<th class="tableblock halign-left valign-top"><p class="tableblock">Instead of</p></th>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>rename()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>setName()</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>discount()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>setNewDiscount()</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>calculate()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>getValue()</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>evaluate()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>getResult()</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>collect()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>getAll()</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The same applies to "test" prefix in unit test classes:
Most methods in these classes are tests, and mostly they are marked by an annotation like <code>@Test</code>.
Moreover, often the containing class contains "Test" in its name.</p>
</div>
<div class="sect3">
<h4 id="exceptions-4">Exceptions</h4>
<div class="paragraph">
<div class="title">Naming conventions</div>
<p>For <em>actual</em> getters and setters, we want to follow the naming convention.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="tell-a-story-in-methods">Tell a story in methods</h3>
<div class="paragraph">
<p>A method should read like a story.
As a method is mostly composed out of other method calls, each method name acts as the heading of the next part of the story.
On the highest level, each called method name is like a heading of a chapter.
Inside the chapter method, each called method name represents a section, and so on.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">void</span> <span class="nf">executeTasks</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">initialize</span><span class="o">();</span>
  <span class="n">prepareCaches</span><span class="o">();</span>
  <span class="n">loopThroughTasks</span><span class="o">();</span>
  <span class="n">storeResults</span><span class="o">();</span>
  <span class="n">cleanup</span><span class="o">();</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="bonus-use-test-as-prefix-for-test-only-helper-classes">Bonus: Use "Test" as Prefix for test-only helper classes</h3>
<div class="paragraph">
<p>This applies more to classes than methods, and is the only guideline geared specifically towards <em>writing</em> code.</p>
</div>
<div class="paragraph">
<p>We sometimes need supporting classes in our unit tests.
Maybe they set up some shared environment, or implement a handler we need for testing.
Such classes should have a "Test" <em>prefix</em> because:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>"Test" <em>suffix</em> is sometimes used to discover actual unit test classes.</p>
</li>
<li>
<p>The prefix removes the class quickly from global searches for real code, both because "T" is late in the alphabet, and fuzzy name search is more sensitive to the beginning of names.</p>
<div class="paragraph">
<p>Example: Our code base contains several <code>ExceptionHandler</code> classes, and we don&#8217;t exactly recall the name of the interesting one.
Of course, we also write tests for exception handling, thus we also have such classes next to our unit tests.
We might first search for <code>*ExHand</code> and get the following list:</p>
</div>
<div class="openblock">
<div class="content">
<div class="ulist">
<ul>
<li>
<p><code>DatabaseExceptionHandler</code></p>
</li>
<li>
<p><code>FatalExceptionHandler</code></p>
</li>
<li>
<p><code>TestDummyExceptionHandler</code></p>
</li>
<li>
<p><code>TestUiExceptionHandler</code></p>
</li>
<li>
<p><code>UiExceptionHandler</code></p>
</li>
</ul>
</div>
</div>
</div>
<div class="paragraph">
<p>We can quickly ignore anything starting with <code>Test</code>, or refine our search to <code>alExHand</code> and hide all test handlers completely.</p>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="charts-worst-to-best-names">Charts: Worst to best names</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="8th-comment-instead-of-method">8<sup>th</sup> Comment instead of method</h3>
<div class="paragraph">
<p>The worst possible method names are non-existing ones.
The following code block is clearly structured in several sections&#8201;&#8212;&#8201;but by comments!</p>
</div>
<div class="listingblock">
<div class="title">Bad example of missing method (names)</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">void</span> <span class="nf">executeTasks</span><span class="o">()</span> <span class="o">{</span>
  <span class="c1">// Initialize</span>
  <span class="n">initEnvironment</span><span class="o">();</span>
  <span class="n">cleanupTempFiles</span><span class="o">();</span>

  <span class="c1">// Prepare Caches</span>
  <span class="n">precalculate</span><span class="o">();</span>
  <span class="n">fillCache</span><span class="o">();</span>

  <span class="c1">// Loop through tasks</span>
  <span class="n">bool</span> <span class="n">done</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
  <span class="k">while</span> <span class="o">(!</span><span class="n">done</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">calculateNextTask</span><span class="o">();</span>
    <span class="n">done</span> <span class="o">=</span> <span class="n">checkMoreWork</span><span class="o">();</span>
  <span class="o">}</span>

  <span class="c1">// Store results</span>
  <span class="n">collectResult</span><span class="o">();</span>
  <span class="n">writeResults</span><span class="o">();</span>

  <span class="c1">// cleanup</span>
  <span class="n">closeFiles</span><span class="o">();</span>
  <span class="n">evictCaches</span><span class="o">();</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This is bad for several reasons:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>When the code evolves, it&#8217;s very easy to put a new line in the wrong section, or forget to update the comment.
It&#8217;s way more likely to update a non-fitting method name than some arbitrary comment.</p>
</li>
<li>
<p>To get a quick overview of the implementation, we have to scan the code for the <em>least expressive</em> part&#8201;&#8212;&#8201;the comments.
We also have to read through all lines, where in reality might be several hundreds of them.</p>
</li>
<li>
<p>With everything in one method, nobody stops us from creating some variables in the "Initialize" section, update them under some condition in the main loop, misuse them while storing results, and then use them erroneously in the "cleanup" section.
In the better version below, we have to make a <em>deliberate choice</em> to pass such values in and out of each section, pushing us towards cleaner code.</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="title">Good refactoring extracting each commented section as separate method</div>
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">void</span> <span class="nf">executeTasks</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">initialize</span><span class="o">();</span>
  <span class="n">prepareCaches</span><span class="o">();</span>
  <span class="n">loopThroughTasks</span><span class="o">();</span>
  <span class="n">storeResults</span><span class="o">();</span>
  <span class="n">cleanup</span><span class="o">();</span>
<span class="o">}</span>

<span class="kt">void</span> <span class="nf">initialize</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">initEnvironment</span><span class="o">();</span>
  <span class="n">cleanupTempFiles</span><span class="o">();</span>
<span class="o">}</span>

<span class="kt">void</span> <span class="nf">prepareCaches</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">precalculate</span><span class="o">();</span>
  <span class="n">fillCache</span><span class="o">();</span>
<span class="o">}</span>

<span class="kt">void</span> <span class="nf">loopThroughTasks</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">bool</span> <span class="n">done</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
  <span class="k">while</span> <span class="o">(!</span><span class="n">done</span><span class="o">)</span> <span class="o">{</span>
      <span class="n">calculateNextTask</span><span class="o">();</span>
      <span class="n">done</span> <span class="o">=</span> <span class="n">checkMoreWork</span><span class="o">();</span>
  <span class="o">}</span>
<span class="o">}</span>

<span class="kt">void</span> <span class="nf">storeResults</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">collectResult</span><span class="o">();</span>
  <span class="n">writeResults</span><span class="o">();</span>
<span class="o">}</span>

<span class="kt">void</span> <span class="nf">cleanup</span><span class="o">()</span> <span class="o">{</span>
  <span class="n">closeFiles</span><span class="o">();</span>
  <span class="n">evictCaches</span><span class="o">();</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This version reads like a story, and we (as a reader) can choose how many details we&#8217;d like to hear.
As an analogy to "The Lord of the Rings", we can tell its story:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>As brief as "Frodo gets the One ring, travels to Mordor, and destroys the jewel."</p>
</li>
<li>
<p>Be a bit more interested in the last part:
"Frodo gets the One ring and travels to Mordor.
He gets captured, but can escape.
Disguised as orc, he crosses the Plateau of Gorgoroth.
Finally, he scales Mount Doom.
When Gollum wrestles the ring off Frodo&#8217;s finger, both the ring and Gollum fall and perish in fire."</p>
</li>
<li>
<p>By reading all 1157 pages of the trilogy.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The same applies to above&#8217;s version.
We can quickly get a brief overview, and easily zoom in to any section of interest.
This gets even easier with a proper editor or IDE that jumps to the implementation, and can navigate backwards on command (similar to a browser).</p>
</div>
<div class="sect3">
<h4 id="exceptions-5">Exceptions</h4>
<div class="paragraph">
<div class="title">Complex algorithms</div>
<p>Some complex algorithms only work by juggling lots of different, always-changing data structures.
It can be hard to cut such algorithms into independent parts.
Don&#8217;t take this as a broad excuse: If our code is not straight out of a textbook or scientific paper, it probably doesn&#8217;t qualify.</p>
</div>
<div class="paragraph">
<div class="title">Performance optimization</div>
<p>If we&#8217;re <em>absolutely</em> sure, and have confirmed by <em>measurements</em>, that some part of code is performance-critical, we might need to sacrifice structure and naming for the sake of performance.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="7th-decompiler-names">7<sup>th</sup> Decompiler names</h3>
<div class="paragraph">
<p>Decompilers turn machine code back into some programming language.
As machine code doesn&#8217;t contain any names, the decompiler must invent them.
Sometimes they can guess, but often they use arbitrary, nonsensical gibberish.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">void</span> <span class="nf">mA0we234__s</span><span class="o">()</span> <span class="o">{</span>
  <span class="c1">// ...</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>These names don&#8217;t tell us anything about the content, but at least we learn that some part of code belongs together, and (hopefully) <em>could</em> find a proper name for that part.</p>
</div>
</div>
<div class="sect2">
<h3 id="6th-same-as-method-content">6<sup>th</sup> Same as method content</h3>
<div class="paragraph">
<p>If we&#8217;re very uncreative how to name a method, we might just repeat the contents of the method.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">int</span> <span class="nf">compareITo0</span><span class="o">(</span><span class="nc">Integer</span> <span class="n">i</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">i</span><span class="o">.</span><span class="na">CompareTo</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This is almost as bad as decompiler names, as it tells us <em>how</em> the method does its job&#8201;&#8212;&#8201;not <em>what</em>.
It also doesn&#8217;t save us much time compared to just reading the code, and doesn&#8217;t give us a more abstract understanding.</p>
</div>
<div class="sect3">
<h4 id="exceptions-6">Exceptions</h4>
<div class="paragraph">
<div class="title">Temporary names during development</div>
<p>While writing a piece of code, we might get disturbed by a block of code.
Then we use our IDE to extract that block into a method&#8201;&#8212;&#8201;and now need a good name.
However, we can easily start with <em>any</em> name, just to remove the disturbance.
Later, possibly after several other changes, we can get back to the method.
Now we understand our implementation better, and can give a fitting name to the method.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="5th-narrate-implementation">5<sup>th</sup> Narrate implementation</h3>
<div class="paragraph">
<p>Just repeating the method content might seem ridiculous, but it&#8217;s very close to this next variant:
narrate the implementation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">boolean</span> <span class="nf">checkIfIIsNotNullOrNegative</span><span class="o">(</span><span class="nc">Integer</span> <span class="n">i</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">i</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="n">i</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We have only a barely visible abstraction, and still have no idea about the context of the method.
The name doesn&#8217;t save us any time compared to just reading the code.
On the contrary: We might start thinking whether the name and the implementation actually say the same, and forget to update the name if we changed the content.</p>
</div>
<div class="sect3">
<h4 id="exceptions-7">Exceptions</h4>
<div class="paragraph">
<div class="title">Rich context</div>
<p>If our context tells everything else, seemingly narrative names can be ok.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">NumberParser</span> <span class="o">{</span>
  <span class="kd">private</span> <span class="nc">String</span> <span class="n">input</span><span class="o">;</span>

  <span class="kd">public</span> <span class="nf">NumberParser</span><span class="o">(</span><span class="nc">String</span> <span class="n">input</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">this</span><span class="o">.</span><span class="na">input</span> <span class="o">=</span> <span class="n">input</span><span class="o">;</span>
  <span class="o">}</span>

  <span class="kd">public</span> <span class="nc">Number</span> <span class="nf">parse</span><span class="o">()</span> <span class="o">{</span>
    <span class="n">checkNotNull</span><span class="o">();</span>
    <span class="n">determineNumberBase</span><span class="o">();</span>
    <span class="n">trim</span><span class="o">();</span>
    <span class="k">return</span> <span class="nf">convert</span><span class="o">();</span>
  <span class="o">}</span>

  <span class="kd">private</span> <span class="kt">void</span> <span class="nf">checkNotNull</span><span class="o">()</span> <span class="o">{</span>
      <span class="k">if</span> <span class="o">(</span><span class="n">input</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
          <span class="k">return</span><span class="o">;</span>

      <span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalValueException</span><span class="o">(</span><span class="s">"input must not be null"</span><span class="o">);</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>checkNotNull()</code> narrates its content, but makes sense both in context of its class, and the story of the <code>parse()</code> method.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="4th-inconsistent-abstraction">4<sup>th</sup> Inconsistent abstraction</h3>
<div class="paragraph">
<p>As each method should tell a story, the names of the called methods should be on a similar level of abstraction.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kt">int</span> <span class="nf">findIndexOf</span><span class="o">(</span><span class="nc">Collection</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">&gt;</span> <span class="n">haystack</span><span class="o">,</span> <span class="nc">String</span> <span class="n">needle</span><span class="o">)</span> <span class="o">{</span>
  <span class="kt">var</span> <span class="n">algorithm</span> <span class="o">=</span> <span class="n">selectSearchAlgorithm</span><span class="o">(</span><span class="n">haystack</span><span class="o">);</span>
  <span class="n">algorithm</span><span class="o">.</span><span class="na">prepare</span><span class="o">();</span>
  <span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="n">algorithm</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">needle</span><span class="o">);</span>
  <span class="n">index</span> <span class="o">=</span> <span class="n">adjustIndexByMinusOneIfSearchAlgorithmIsOneBased</span><span class="o">(</span><span class="n">algorithm</span><span class="o">,</span> <span class="n">index</span><span class="o">);</span>
  <span class="k">return</span> <span class="n">index</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We have a clear story here: We select a good algorithm, prepare it, find our needle, and adjust the returned index to hide details of different algorithms.
The name <code>adjustIndexByMinusOneIfSearchAlgorithmIsOneBased()</code> tells us what the method does, but on a very different level of abstraction than the other called methods.
When we think about the problem to solve on this level, we get distracted by this level of detail.</p>
</div>
</div>
<div class="sect2">
<h3 id="3rd-leak-implementation-details">3<sup>rd</sup> Leak implementation details</h3>
<div class="paragraph">
<p>The method name should tell <em>what</em> it does, not <em>how</em> it achieves that goal.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">StringComparer</span> <span class="o">{</span>
  <span class="kt">boolean</span> <span class="nf">levenshteinDistanceSmallEnough</span><span class="o">(</span><span class="nc">String</span> <span class="n">left</span><span class="o">,</span> <span class="nc">String</span> <span class="n">right</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="n">levenshtein</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Levenshtein</span><span class="o">(</span><span class="n">left</span><span class="o">,</span> <span class="n">right</span><span class="o">);</span>
    <span class="k">return</span> <span class="n">levenshtein</span><span class="o">.</span><span class="na">distance</span><span class="o">()</span> <span class="o">&lt;</span> <span class="no">MAX_DISTANCE</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Inside this <code>StringComparer</code>, we determine if the strings <code>left</code> and <code>right</code> are sufficiently similar.
<a href="https://en.wikipedia.org/wiki/Levenshtein_distance">Levenshtein distance</a>
is probably a good algorithm for that task, but we don&#8217;t need to bother users of <code>StringComparer</code> with that detail.</p>
</div>
</div>
<div class="sect2">
<h3 id="2nd-too-abstract">2<sup>nd</sup> Too abstract</h3>
<div class="paragraph">
<p>Good names do consider their context, but assuming a too broad or abstract context doesn&#8217;t help either.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">StringComparer</span> <span class="o">{</span>
  <span class="kt">boolean</span> <span class="nf">equalsOcrResult</span><span class="o">(</span><span class="nc">String</span> <span class="n">candidate</span><span class="o">,</span> <span class="nc">String</span> <span class="n">ocrResult</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="n">levenshtein</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Levenshtein</span><span class="o">(</span><span class="n">candidate</span><span class="o">,</span> <span class="n">ocrResult</span><span class="o">);</span>
    <span class="k">return</span> <span class="n">levenshtein</span><span class="o">.</span><span class="na">distance</span><span class="o">()</span> <span class="o">&lt;</span> <span class="no">MAX_DISTANCE</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This is the same implementation as above, but the names assume we use it in the context of
<a href="https://en.wikipedia.org/wiki/Optical_character_recognition">optical character recognition</a>.
There&#8217;s nothing specific about OCR on <code>StringComparer</code>, we could perfectly use it in other contexts.
Users might be thrown off by the misleading names.</p>
</div>
</div>
<div class="sect2">
<h3 id="1st-just-right">1<sup>st</sup> Just right</h3>
<div class="paragraph">
<p>Finally, an (almost) optimally named method.
Depending on our team&#8217;s conventions, we might need to prepend some verb to the name, e.g. <code>compareSimilarity()</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">class</span> <span class="nc">StringComparer</span> <span class="o">{</span>
  <span class="kt">double</span> <span class="nf">similarity</span><span class="o">(</span><span class="nc">String</span> <span class="n">candidate</span><span class="o">,</span> <span class="nc">String</span> <span class="n">baseline</span><span class="o">)</span> <span class="o">{</span>
    <span class="kt">var</span> <span class="n">levenshtein</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Levenshtein</span><span class="o">(</span><span class="n">candidate</span><span class="o">,</span> <span class="n">baseline</span><span class="o">);</span>
    <span class="kt">int</span> <span class="n">distance</span> <span class="o">=</span> <span class="n">levenshtein</span><span class="o">.</span><span class="na">distance</span><span class="o">();</span>

    <span class="k">return</span> <span class="o">((</span><span class="kt">double</span><span class="o">)</span> <span class="n">distance</span><span class="o">)</span> <span class="o">-</span> <span class="n">candidate</span><span class="o">.</span><span class="na">length</span><span class="o">();</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The name clearly states <em>what</em> the method does, while hiding implementation details.
It makes sense in its context without repeating parts of it, follows conventions, and doesn&#8217;t contain "get".
The parameter names are easy to distinguish, and state their purpose.
All called methods tell a story.</p>
</div>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="Software architecture" /><summary type="html"><![CDATA[Everybody wants well-named methods&#8201;&#8212;&#8201;but what does that mean? We discuss the purpose of method names, guidelines for choosing them, and look at good and bad examples.]]></summary></entry><entry><title type="html">SysML v2 language in LionWeb</title><link href="https://www.f1re.io/2025-04-15/sysml2-in-lionweb" rel="alternate" type="text/html" title="SysML v2 language in LionWeb" /><published>2025-04-15T00:00:00+00:00</published><updated>2025-04-15T00:00:00+00:00</updated><id>https://www.f1re.io/2025-04-15/sysml2-in-lionweb</id><content type="html" xml:base="https://www.f1re.io/2025-04-15/sysml2-in-lionweb"><![CDATA[<div class="paragraph">
<p>The interoperability of modeling frameworks is an important condition for creating an ecosystem of modeling tools, where one can mix and match components from various technologies and benefit from the best capabilities each tool has to offer.
The <a href="https://lionweb.io">LionWeb protocol</a> was started with the mission to achieve such interoperability between modeling frameworks and language workbenches.
By connecting an MDE (model driven engineering) tool to the LionWeb protocol, we make it possible to exchange metamodels (or languages) and models between our tool and the other MDE tools, that support LionWeb protocol.</p>
</div>
<div class="paragraph">
<p>To demonstrate the benefits of LionWeb, I applied it to the SysML v2 language, a general-purpose modeling language, that is highly anticipated in the world of MBSE (Model Based System Engineering).
The SysML v2 language is being developed by a team from <a href="https://www.omg.org/spec/SysML/2.0/Beta2/About-SysML">Object Management Group (OMG)</a> and is being prototyped in the <a href="https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation">open-source pilot implementation</a>.
The pilot implementation of SysML v2 uses Eclipse Modeling Framework (EMF) for capturing the structure of the language and Xtext for providing its textual notation.</p>
</div>
<div class="paragraph">
<p>The EMF implementation of SysML v2 provides an important reference definition and is used by early adopters and the community to validate the language design and to experiment with the technologies such as formal analysis of SysML v2 models.
The LionWeb protocol allows for opening up this SysML v2 implementation to the other modeling frameworks from the ecosystem, <a href="https://www.jetbrains.com/mps/">JetBrains MPS</a> and <a href="https://www.freon4dsl.dev/">Freon</a>.
JetBrains MPS is a powerful and mature language workbench.
Its projectional editor supports a wide range of domain-specific notations, from text to tables, formulas, and diagrams.
Freon provides a highly-customizable language editor in a web browser.
In addition to an editor, we can benefit from scoping, typing, constraints validation, interpretation and model transformations.
The LionWeb protocol connects them all and allows for using the best of all worlds for SysML v2.</p>
</div>
<div class="sect1">
<h2 id="transferring-a-language-from-one-modeling-framework-to-another">Transferring a language from one modeling framework to another</h2>
<div class="sectionbody">
<div class="olist arabic">
<ol class="arabic">
<li>
<p>As EMF Ecore is supported by the LionWeb protocol, it is possible to export SysML v2 (i.e., its ecore meta-model from the pilot implementation) to the LionWeb Json format.</p>
</li>
<li>
<p>We import the resulting LionWeb Json into two other language workbenches, supported by LionWeb: <a href="https://www.jetbrains.com/mps/">JetBrains MPS</a> and <a href="https://www.freon4dsl.dev/">Freon</a>:
<span class="image"><img src="../../images/sysml2-in-lionweb/reference-architecture-applied.png" alt="reference architecture applied" width="600"></span></p>
</li>
<li>
<p>The import of a LionWeb language into MPS and Freon results into automatic generation of the language definition artifacts in these tools:</p>
</li>
</ol>
</div>
<table class="tableblock frame-none grid-none fit-content">
<colgroup>
<col>
<col>
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top" rowspan="2"><div class="content"><div class="paragraph">
<p>A fragment of the metamodel of the SysML v2 language defined in Ecore: <span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-ecore-metamodel.png" alt="sysml2 ecore metamodel" width="600"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>A fragment of the corresponding metamodel of SysML v2 generated in JetBrains MPS: <span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-mps-ast.png" alt="sysml2 mps ast" width="700"></span></p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>A fragment of the corresponding language definition of SysML v2 generated in Freon (~1100 LOC in total): <span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-freon-ast.png" alt="sysml2 freon ast" width="350"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>There are about 180 concepts in the pilot metamodel of SysML v2, not counting their properties and cross-references.
With LionWeb, we transferred all these concepts, their properties and cross-references, from one language definition format (Ecore) to two other formats (MPS structure definition and Freon AST), automatically and without even bothering what these formats look like.
Just imagine how much work would it take to recreate the SysML v2 metamodel in MPS or Freon from scratch!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="instantiating-language-models">Instantiating language models</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Now as we have the SysML v2 language structure in MPS and Freon, we build the corresponding language infrastructure.
This includes, among others, a default reflective editor for the SysML v2 language.
Thus, we can instantiate a SysML v2 model using the default editor.</p>
</div>
<div class="paragraph">
<p>As a reference, I take this example SysML v2 model from the pilot implementation library, shown here both in the Xtext textual notation and as the underlying EMF tree:
<span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-model-in-eclipse.png" alt="An example of a SysML v2 model in Eclipse (Xtext-based pilot implementation and its visualization)"></span></p>
</div>
<div class="paragraph">
<p>In the MPS reflective editor, a model appears with the placeholders for all its properties and references.
This is the default editor, automatically generated from the metamodel of the SysML v2 language.
For the actual use, we need to create a custom editor for the SysML v2 language, in the same way as Xtext provides the custom textual notation for the ecore meta-model of SysML v2 in EMF.
<span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-model-in-mps.png" alt="An example of a SysML v2 model in MPS (default reflective editor)"></span></p>
</div>
<div class="paragraph">
<p>In the Freon editor, the situation is the same: all the properties and features of the <code>PictureTaking package</code> are shown by default, as this editor is generated automatically from the meta-model.
To make it usable, we need to define a custom editor.
<span class="image"><img src="../../images/sysml2-in-lionweb/sysml2-model-in-freon.png" alt="An example of a SysML v2 model in Freon (default projection editor)"></span></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="next-steps">Next steps</h2>
<div class="sectionbody">
<div class="paragraph">
<p>What we have achieved so far, is transferring the abstract structure of a language from one tool to another.
This is only the first step.
Here are some further steps that we can take to leverage the benefits of our ecosystem of interoperable language engineering tools.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Using LionWeb protocol, automatically transfer SysML v2 models on the M1 level, from one tool to another.
The LionWeb implementation that we use in our exercise already allows for transferring M1-models between the tools.
We haven&#8217;t tried it yet for the SysML v2 language.</p>
</li>
<li>
<p>Enhance SysML v2 language with custom tailored notations, constraints, and evaluations in MPS and Freon.
Just imagine that we could use MPS <a href="http://mbeddr.com/mps-platform-docs/languages/kernelf/tour/solutions/KernelFTour/screenshots/Expressions_2_Math/Expressions_2_Math/">KernelF</a> language notation for the KerML expressions of SysML v2:</p>
</li>
</ul>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/sysml2-in-lionweb/mps-kernelf-example1.png" alt="mps kernelf example1" width="230"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/sysml2-in-lionweb/mps-kernelf-example2.png" alt="mps kernelf example2" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="ulist">
<ul>
<li>
<p>Adapt SysML v2 to a concrete system domain by building a DSL (domain-specific language) on top of it.
This is what language workbenches like MPS are good at: building domain-specific extensions on top of a language.</p>
</li>
<li>
<p>Develop model transformations and generators using powerful tools of MPS.</p>
</li>
</ul>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="LionWeb" /><category term="SysML2" /><category term="JetBrains MPS" /><summary type="html"><![CDATA[In this blog post I describe how I transferred the SysML v2 language from its EMF implementation into MPS and Freon language workbenches, using the LionWeb protocol]]></summary></entry><entry><title type="html">F1RE Partners with Freon for Web-Based DSL Development</title><link href="https://www.f1re.io/2025-03-12/freon-partnering" rel="alternate" type="text/html" title="F1RE Partners with Freon for Web-Based DSL Development" /><published>2025-03-12T00:00:00+00:00</published><updated>2025-03-12T00:00:00+00:00</updated><id>https://www.f1re.io/2025-03-12/freon-partnering</id><content type="html" xml:base="https://www.f1re.io/2025-03-12/freon-partnering"><![CDATA[<div class="paragraph">
<p>We’re excited to announce that F1RE is partnering with Freon, a platform for web-based domain-specific language (DSL) development.</p>
</div>
<div class="paragraph">
<p>Freon is an advanced language workbench that makes it easier to design and implement DSLs.
Unlike many other DSL tooling solutions, Freon is designed to be highly accessible — even for non-developers.
Its intuitive web-based framework allows domain experts to define and refine models without needing any programming expertise.
This makes Freon a great fit for teams that need powerful language tools but don’t want to be locked into complex or overly technical solutions.</p>
</div>
<div class="paragraph">
<p>At F1RE, we’re always looking for the best tools to support our clients in DSL development, and Freon’s flexibility and user-friendliness makes it a perfect new alternative.
Whether you’re developing a language for a specialized industry or creating a custom tool for internal use, Freon makes it easier to bring those ideas to life.</p>
</div>
<div class="sect1">
<h2 id="why-freon">Why Freon?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Freon’s framework includes five dedicated generators, each covering an essential part of language development:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/freon-partnering/freon-framework.png" alt="freon framework">
</div>
<div class="title">Figure 1. Freon&#8217;s framework for language development</div>
</div>
<div class="paragraph">
<p>Language Structure – Define the core concepts, properties, and relationships of your language.
Editor – Customize how your language is represented and edited.
Scoper – Manage references and name resolution.
Typer – Ensure consistency by defining type rules.
Validator – Set rules that enforce model correctness with real-time feedback.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/freon-partnering/freon-stand-out.png" alt="freon stand out">
</div>
<div class="title">Figure 2. What makes Freon stand out</div>
</div>
<div class="paragraph">
<p>Freon fully supports <a href="https://lionweb.io/">LionWeb</a>, meaning there’s no tool lock-in.
Any LionWeb-enabled tool can read and process your languages and models. (www.lionweb.io)</p>
</div>
<div class="paragraph">
<p>With this partnership, F1RE is reinforcing its commitment to making DSL development more accessible, flexible, and scalable for business.
If you’re working or needing a DSLs and want to explore how Freon can fit into your workflow, get in touch — we’d love to help you get started!</p>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="F1RE" /><category term="DSL" /><category term="Freon" /><summary type="html"><![CDATA[We’re excited to announce that F1RE is partnering with Freon, a platform for web-based domain-specific language (DSL) development.]]></summary></entry><entry><title type="html">Model First, AI Second: The F1RE Approach</title><link href="https://www.f1re.io/2024-11-12/model-first-ai-next" rel="alternate" type="text/html" title="Model First, AI Second: The F1RE Approach" /><published>2024-11-12T00:00:00+00:00</published><updated>2024-11-12T00:00:00+00:00</updated><id>https://www.f1re.io/2024-11-12/model-first-ai-next</id><content type="html" xml:base="https://www.f1re.io/2024-11-12/model-first-ai-next"><![CDATA[<h1>Model First, AI Second: The F1RE Approach</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p><span class="text-sm text-gray-600">⏱️ 13 minute read</span></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="background">Background</h2>
<div class="sectionbody">
<div class="paragraph">
<p>At F1RE, we specialize in model-driven software engineering (MDE). For organizations using this in their daily operations, the benefits are clear.
To those new to this field, model-driven engineering may seem like a specialized approach.
But, MDE has demonstrated its value through successful implementations across industries, from automotive to aerospace. Consider how the <a href="https://www.esa.int/Enabling_Support/Space_Engineering_Technology/Shaping_the_Future/Goodbye_Documents_Hello_Models_A_Model-based_Approach_to_System_Engineering">ESA successfully moved from documents to models</a>.</p>
</div>
<div class="paragraph">
<p>In this article, we share our perspective on why MDE becomes even more crucial in the age of AI - not as a competitor to AI, but as a foundation that can help organizations get the most value from AI while maintaining control and reliability.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-gen-ai-hype-a-view-from-both-sides">The Gen-AI Hype: A View from Both Sides</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Here&#8217;s the elephant in the room - Building specialized MDE tools would be a hard sell today considering the generative AI hype. <em>"Why don&#8217;t you just dump the domain knowledge in the form of some documents and ask ChatGPT to create what you need"</em> would not be a surprising rebuttal.
Everyone&#8217;s rushing to "throw AI at it" these days for a fast result. At F1RE we don&#8217;t think this is smart.
This creates more problems than it solves and you would lose control over what is being done with what.</p>
</div>
<div class="paragraph">
<p>Having worked at the intersection of model-driven engineering and AI across both industry and academia, I&#8217;ve seen how these two approaches interact in practice.
 In industry, I&#8217;ve worked with domain-specific languages for safety-critical systems and most recently led projects developing AI-enabled medical chatbots.
 Meanwhile, in academia, I co-authored a <a href="https://aclanthology.org/2024.findings-acl.939/">recent study published in ACL 2024</a> that looked at how these AI models actually understand code, and the findings were eye-opening. Despite their seemingly impressive outputs, these models don&#8217;t really grasp the meaningful connections in code - they just recognize patterns between similar-looking pieces.
 It&#8217;s like someone who can complete sentences in a conversation by pattern matching, without actually understanding how the different parts of the sentence relate to each other. Even more surprisingly, we found that making these AI models bigger (even up to billions of parameters) actually made them worse at capturing these important relationships, not better.</p>
</div>
<div class="paragraph">
<p>I saw these same limitations play out with the medical chatbots. Despite promising initial results, we struggled to make the system&#8217;s answers consistently reliable, even with sophisticated retrieval techniques.
Our experience matches what we&#8217;re seeing across the industry - <a href="https://www.cio.com/article/3540579/devs-gaining-little-if-anything-from-ai-coding-assistants.html">developers using AI assistants are seeing 40% more bugs</a>, and <a href="https://www.gartner.com/en/newsroom/press-releases/2024-07-09-gartner-survey-finds-64-percent-of-customers-would-prefer-that-companies-didnt-use-ai-for-customer-service">Gartner&#8217;s survey of 5,728 customers</a> revealed that "while customer service leaders are eager to adopt AI, 64% of customers remain concerned about such an adoption."</p>
</div>
<div class="paragraph">
<p>These concerns extend far beyond individual experiences. In safety-critical systems, even small inconsistencies in AI outputs can have serious implications.
The challenge isn&#8217;t just about fixing bugs - it&#8217;s about guaranteeing reliable behavior in situations where mistakes could be costly (like affecting patient safety). This widespread experience across the industry shows why we need a more disciplined approach to AI integration, especially in domains where reliability matters.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-challenge-with-current-ai-approaches">The challenge with current AI approaches</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The fundamental issue isn&#8217;t just about bugs or customer concerns - it&#8217;s about four critical properties that any business-critical system must have: determinism, reliability, verifiability, and explainability.
In the following subsections, we&#8217;ll examine each of these properties in detail, comparing how traditional systems and generative AI solutions measure up against them.
For each property, we&#8217;ll provide clear definitions and concrete examples that illustrate why simply 'adding AI' to existing processes often creates more problems than it solves:</p>
</div>
<div class="sect2">
<h3 id="1-determinism">1. Determinism</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>A property that guarantees that a system always produces the same output for the same input.</p>
</div>
</td>
</tr>
</table>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Traditional System</th>
<th class="tableblock halign-left valign-top">Generative AI</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">A banking transaction with specific inputs always follows the same processing path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The same prompt about transaction processing might yield different responses each time</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Flight control software responds identically to given conditions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Asking about flight parameters could generate varying suggestions</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="2-reliability">2. Reliability</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The ability to consistently perform according to specifications without failure.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In professional cycling team management, where scheduling decisions impact athlete health and team performance:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Traditional System</th>
<th class="tableblock halign-left valign-top">Generative AI</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Never schedules races violating UCI* regulations<br>
<span class="small"><em>* International Cycling Federation, the governing body of major cycling events</em></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Might suggest non-existent races</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Enforces mandatory recovery periods between races</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Could schedule impossible race combinations</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Respects rider specialties and qualifications</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">May create resource conflicts</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="3-verifiability">3. Verifiability</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The ability to prove that a system&#8217;s behavior matches its specifications.</p>
</div>
</td>
</tr>
</table>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Traditional System</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Generative AI</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">System behavior can be mathematically proven to meet safety requirements through formal verification methods</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Cannot provide mathematical proof that outputs will always conform to specified requirements</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Automated testing can verify compliance with every single business rule in the specification</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Testing can only sample a tiny fraction of possible outputs - complete verification impossible</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Every possible decision scenario can be analyzed to prove the system will always stay within defined limits</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">No way to verify that all possible situations will be handled according to business rules</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="4-explainability">4. Explainability</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The capacity to provide clear, consistent reasoning for decisions.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In autonomous vehicle decision-making:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Traditional System</th>
<th class="tableblock halign-left valign-top">Generative AI</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Vehicle slowed because:<br>
 Pedestrian detected at 15m distance<br>
 Road surface friction reduced by 40%<br>
 Safety protocol 7.2 activated<br></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Different explanations each time:<br>
 "Considering traffic patterns&#8230;&#8203;"<br>
 "Based on movement in the area&#8230;&#8203;"<br>
 "Looking at environmental conditions&#8230;&#8203;"<br></p>
</div></div></td>
</tr>
</tbody>
</table>
<h3 id="the-root-of-the-problem" class="discrete">The Root of the Problem</h3>
<div class="paragraph">
<p>These four properties - determinism, reliability, verifiability, and explainability - reveal systemic issues with current AI approaches.
But why do these problems persist? The core challenge lies in generative AI&#8217;s fundamental design goal: <em>to be flexible enough to handle any input and generate plausible-looking outputs across unlimited domains</em>.
This very flexibility makes it inherently difficult to constrain these systems within specific business rules or domain requirements. (While there are other applications of AI focused on specific, bounded tasks that have proven more reliable - which we&#8217;ll discuss later in this article.)</p>
</div>
<div class="paragraph">
<p>An interesting perspective on this comes from a <a href="https://www.scientificamerican.com/article/chatgpt-isnt-hallucinating-its-bullshitting/">Scientific American analysis</a> that reframes how we think about AI&#8217;s inconsistencies.
As the article points out,</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>what we commonly call AI "hallucinations" are more accurately described as "bullshitting" -  the AI isn&#8217;t trying and failing to represent reality, it&#8217;s simply generating plausible-looking text without any regard for truth. To quote the article verbatim - "<em>we can see &#8230;&#8203; that nothing about the modeling ensures that the outputs accurately depict anything in the world</em>". In philosophical terms, the bullshitter, unlike a liar, doesn&#8217;t care about the truth - they just aim to produce convincing output.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Instead of addressing the fundamental issue of domain control, current approaches try to fix these shortcomings through various bolt-on solutions:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Approach</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Limitation</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Creating more detailed prompts</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Still can&#8217;t guarantee consistent interpretation, just more verbose instructions that may or may not be followed</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Fine-tuning models with domain data</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">May learn patterns but not rules; expensive and time-consuming with no guarantees of consistent behavior</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Using RAG (Retrieval Augmented Generation)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">While it can access correct reference data, may still combine information incorrectly or make invalid logical leaps</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Retraining models</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Extremely expensive, time-consuming, and still lacks formal guarantees of rule compliance</p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Key Insight: These approaches treat symptoms rather than the root cause - they attempt surface-level fixes rather than establishing a robust domain foundation first. They all share the fundamental weakness of trying to teach rules to a system designed for flexibility rather than consistency.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-f1re-vision-model-driven-engineering-first">The F1RE vision: Model-Driven Engineering First</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Having seen how bolt-on approaches fail to address the fundamental challenges of AI integration, we propose a different path forward: Instead of teaching AI rules through prompts or documents, we encode constraints into the system&#8217;s structure itself using our three layer vision. Let&#8217;s examine this approach:</p>
</div>
<div class="sect2">
<h3 id="step-1-model-your-domain-the-domain-layer">Step 1: Model Your Domain (The Domain layer)</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Create a Domain-Specific Language (DSL) that precisely captures what matters in your domain - its concepts, rules, and relationships.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Before looking at examples, let&#8217;s understand the three key elements of domain modeling:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Concepts:</strong> The "things" in your domain - like products in a store or patients in a hospital</p>
</li>
<li>
<p><strong>Rules:</strong> The step-by-step procedures that must be followed - like "check ID before selling alcohol"</p>
</li>
<li>
<p><strong>Constraints:</strong> The absolute boundaries that can&#8217;t be crossed - like "no one under 18 can buy alcohol"</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Let&#8217;s see some high-level examples of how different industries could structure their domain knowledge using these elements:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Domain</th>
<th class="tableblock halign-left valign-top">Key Elements</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Healthcare</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Concepts: Patient, Treatment, Medication<br>
Rules: If patient has diabetes, check blood sugar before treatment<br>
Constraints: Only certified doctors can prescribe Class A drugs</p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Financial Trading</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Concepts: Trade, Portfolio, Risk Level<br>
Rules: Calculate risk exposure before each trade<br>
Constraints: No single trade can exceed 5% of portfolio value</p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Manufacturing</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Concepts: Product, Process, Quality Check<br>
Rules: Follow specified assembly sequence for each product<br>
Constraints: Machine operating temperature must stay below 85°C</p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p><strong>Key Benefit:</strong> Invalid operations become impossible by design. Just as you can&#8217;t overdraw a savings account with proper banking software, you can&#8217;t violate domain rules in a well-modeled system.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="step-2-make-your-models-executable-the-execution-layer">Step 2: Make Your Models Executable (The execution layer)</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Transform models from documentation into active systems that enforce rules automatically.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Think of this step as bringing your domain rules to life. Instead of having rules in manuals or documentation that people need to read and follow, we create systems that automatically enforce these rules. It&#8217;s like the difference between:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Having a sign that says "Do not enter if the room is full" (passive)</p>
</li>
<li>
<p>Having an automatic counter that locks the door when capacity is reached (active)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This automatic enforcement means people can&#8217;t accidentally break rules - the system simply won&#8217;t allow invalid operations. It&#8217;s similar to how ATMs won&#8217;t let you withdraw more money than you have in your account, no matter what buttons you press.</p>
</div>
<div class="paragraph">
<p>This transformation from static documentation to active enforcement represents a fundamental shift in how organizations handle domain rules. Here&#8217;s how it looks across industries:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Domain</th>
<th class="tableblock halign-left valign-top">Transformation</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Automotive</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Traditional: Safety requirements in PDF manuals<br>
Executable: Automated validation of every design change against safety rules</p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Aviation</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Traditional: Flight procedures in manuals<br>
Executable: System automatically validates flight plans against weather, fuel, and crew constraints</p>
</div></div></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Healthcare</p></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>Traditional: Treatment protocols in guidelines<br>
Executable: System enforces protocol compliance in real-time</p>
</div></div></td>
</tr>
</tbody>
</table>
</div>
<div class="sect2">
<h3 id="step-3-integrate-ai-strategically-the-ai-layer">Step 3: Integrate AI Strategically (The AI layer)</h3>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Choose specific AI technologies based on task requirements and necessary guarantees.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>While generative AI&#8217;s flexibility makes it challenging to control, there exists a spectrum of AI technologies that can provide reliable results when properly constrained.
A striking example is DeepMind&#8217;s AlphaFold, which <a href="https://medium.com/syncedreview/deepmind-alphafold-delivers-unprecedented-progress-on-protein-folding-789fcc1420ea">revolutionized protein structure prediction</a> by focusing on a specific scientific challenge.
This specialized AI system achieved in two years what biochemists had struggled with for 50 years, demonstrating how focused AI applications can deliver remarkable value. By combining such focused AI capabilities with model-driven engineering, we can get the best of both worlds: the reliability of deterministic domain models and the predictive power of AI.</p>
</div>
<div class="paragraph">
<p>While building the AI layer, we carefully add AI capabilities - but only after we have our domain rules firmly in place. Think of it like building a house:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>First, you need a solid foundation (your domain model that defines what&#8217;s valid)</p>
</li>
<li>
<p>Then you build strong walls (executable rules that enforce constraints)</p>
</li>
<li>
<p>Finally, you add specialized AI tools for specific tasks (predictions, pattern recognition, and analysis)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This approach ensures AI operates within your domain&#8217;s boundaries.
Instead of hoping AI will learn and follow your rules, you&#8217;re building a system where AI literally cannot break them.
It&#8217;s like giving AI a coloring book with clear lines - it can be creative with colors, but can&#8217;t color outside the lines you&#8217;ve defined.</p>
</div>
<div class="paragraph">
<p>Different AI approaches offer distinct benefits and guarantees. Understanding these helps us choose the right tool for each task:</p>
</div>
<div class="sect3">
<h4 id="specialized-ai-systems">Specialized AI Systems</h4>
<div class="paragraph">
<p>These are AI tools designed for specific, bounded tasks - from simple supervised learning techniques like <a href="https://en.wikipedia.org/wiki/Decision_tree_learning">decision tree learning</a> that follow clear if-then rules (like qualifying customers for loans) to sophisticated deep learning models trained on specific tasks (like <a href="https://deepmind.google/technologies/alphafold/">AlphaFold</a>'s protein structure prediction). Unlike generative AI which aims to be a jack-of-all-trades, these systems are a good fit for tasks requiring predictable, verifiable results because they guarantee the following properties:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Predictable Behavior:</strong> Like a calculator, gives the same output for the same input every time</p>
</li>
<li>
<p><strong>Clear Confidence Levels:</strong> Tells you exactly how sure it is about predictions (e.g., "85% confident this patient needs urgent care" with mathematical proof)</p>
</li>
<li>
<p><strong>Traceable Decisions:</strong> Can explain exactly why it made each prediction (e.g., "40% of the risk score came from blood pressure, 30% from age&#8230;&#8203;")</p>
</li>
<li>
<p><strong>Direct Domain Mapping:</strong> Works directly with your domain rules (e.g., if your medical system has 20 vital signs to check, specialized AI models work with exactly those 20 measurements - no more, no less) <span class="small">{ For more on this, read about <a href="https://en.wikipedia.org/wiki/Feature_engineering">extracting features</a> from raw domain data}</span></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here are some examples of tasks where specialized AI technologies can be useful.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Domain</th>
<th class="tableblock halign-left valign-top">Application Examples</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Medical Diagnosis</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Predict patient risks with exact confidence levels and clear evidence of which symptoms led to the prediction</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Financial Risk</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Calculate precise risk scores where you can trace every factor that influenced the score</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Manufacturing</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Predict equipment failures with specific timeframes and clear reasoning about which measurements indicated problems</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="generative-ai">Generative AI</h4>
<div class="paragraph">
<p>For creative tasks where flexibility matters more than absolute precision, GenAI is handy (but needs to be kept on a tight leash) because it has the following key characteristics:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Creative Flexibility:</strong> Can generate new ideas and content, but may give different outputs each time</p>
</li>
<li>
<p><strong>Broader Knowledge:</strong> Can suggest new approaches based on general knowledge</p>
</li>
<li>
<p><strong>Needs Validation:</strong> Like a creative assistant, its suggestions must always be checked against domain rules</p>
</li>
<li>
<p><strong>Indirect Domain Mapping:</strong> Understands general concepts but needs guidance to follow specific domain rules</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Here are some examples of tasks where generative AI technologies can be useful.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Domain</th>
<th class="tableblock halign-left valign-top">Application Examples</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Legal</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Draft initial contracts which lawyers then review and correct</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Software</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Suggest code that must be verified against your system&#8217;s rules</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Marketing</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Create content drafts that experts review for accuracy and brand alignment</p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p><strong>Key Insight:</strong>  Specialized AI is like having a highly specialized expert who always follows your rules and can explain their reasoning. Generative AI is like having a creative assistant who brings new ideas but needs supervision to ensure they follow your domain rules correctly. Both are valuable when used appropriately and constrained by your domain model.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="how-it-all-works-together">How It All Works Together</h3>
<div class="paragraph">
<p>While we&#8217;ve laid out our vision for integrating AI with domain models, it&#8217;s important to understand how this could work in practice.
Let&#8217;s examine a proposed flow that demonstrates how our model-first approach could ensure reliable AI integration through automated domain validation.</p>
</div>
<div class="imageblock text-center">
<div class="content">
<img src="../../images/modelfirstainext/sequence_flow.png" alt="System Flow">
</div>
<div class="title">Figure 1. System Flow</div>
</div>
<div class="paragraph">
<p>In this diagram, rectangles represent system components (User, GenAI, Domain Layer, and Specialized AI), solid arrows show direct commands or requests, and dotted arrows indicate responses or conditional flows that depend on validation results.
Every interaction flows through the Domain Layer, ensuring all operations respect our defined rules and constraints.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s explore each pathway with a concrete example:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Draft Creation with GenAI</dt>
<dd>
<p>Imagine drafting a manufacturing process document:</p>
<div class="ulist">
<ul>
<li>
<p>User requests GenAI to create an initial process draft</p>
</li>
<li>
<p>GenAI generates content following provided guidelines</p>
</li>
<li>
<p>Domain Layer validates that all safety steps are included and in correct order</p>
</li>
<li>
<p>User receives a compliant draft ready for review</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">Manual Artifact Creation</dt>
<dd>
<p>Consider creating a new trading rule:</p>
<div class="ulist">
<ul>
<li>
<p>User directly inputs trading parameters into the system</p>
</li>
<li>
<p>Domain Layer checks against position limits and regulatory requirements</p>
</li>
<li>
<p>User receives immediate feedback if any constraints are violated</p>
</li>
<li>
<p>Valid rules are accepted into the system</p>
</li>
</ul>
</div>
</dd>
<dt class="hdlist1">Intelligent Analysis</dt>
<dd>
<p>Take predictive maintenance in manufacturing:</p>
<div class="ulist">
<ul>
<li>
<p>User requests analysis of equipment performance data</p>
</li>
<li>
<p>Specialized AI models access historical data within domain constraints</p>
</li>
<li>
<p>Domain Layer ensures predictions respect operating limits</p>
</li>
<li>
<p>User receives validated predictions about potential equipment failures</p>
</li>
</ul>
</div>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Each pathway demonstrates how the Domain Layer acts as a guardian, ensuring all operations - whether human-initiated, AI-generated, or AI-analyzed - remain within established business rules and constraints.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p><strong>Key Insight:</strong> This model-first approach shows how different AI types serve distinct purposes: GenAI as an optional drafting aid and specialized AI as a core prediction engine. Both are constrained by domain models, ensuring system reliability regardless of which components are used.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph text-center">
<p><strong><em>In summary, Build reliable systems first, then innovate with AI.</em></strong></p>
</div>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><summary type="html"><![CDATA[We describe the envisioned approach of F1RE when integrating AI into systems]]></summary></entry><entry><title type="html">Domain Specific Languages</title><link href="https://www.f1re.io/2024-11-11/domain-specific-languages" rel="alternate" type="text/html" title="Domain Specific Languages" /><published>2024-11-11T00:00:00+00:00</published><updated>2024-11-11T00:00:00+00:00</updated><id>https://www.f1re.io/2024-11-11/domain-specific-languages</id><content type="html" xml:base="https://www.f1re.io/2024-11-11/domain-specific-languages"><![CDATA[<div class="paragraph">
<p>In this blog post I will give a brief introduction to Domain specific Languages (DSLs).
For a more elaborate description, I recommend reading various resources available online as well as whole books on DSLs, listed at the bottom of this post.</p>
</div>
<div class="sect1">
<h2 id="software-languages">Software languages</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Software languages are meant for communicating instructions to machines by people.
For this, a software language constitutes a system of notation for writing programs.
Such a system is usually defined in the form of the language syntax and semantics.
Syntax defines the form that programs can have.
Semantics defines the meaning of the programs.</p>
</div>
<div class="paragraph">
<p>For example, there exist many programming languages that are widely used in developing software:</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
<col style="width: 20%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/dsls-and-language-workbenches/ruby-logo.png" alt="ruby logo" width="50"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/dsls-and-language-workbenches/typescript-logo.png" alt="typescript logo" width="50"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/dsls-and-language-workbenches/java-logo.png" alt="java logo" width="50"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/dsls-and-language-workbenches/cpp-logo.png" alt="cpp logo" width="50"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/dsls-and-language-workbenches/python-logo.png" alt="python logo" width="50"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="sect1">
<h2 id="domain-specific-languages">Domain specific languages</h2>
<div class="sectionbody">
<div class="paragraph">
<p>While general-purpose programming languages can in principle be used for developing any type of application (from web-based SaaS to embedded software), each domain-specific language is specialized in a particular application domain.</p>
</div>
<div class="paragraph">
<p>For example, the following DSLs are good for expressing machine tasks in their particular domains, but hardly can be used for building an arbitrary software application.
MATLAB is useful for describing matrix calculations, but we hardly would use it for programming a web application.
SQL is meant for querying databases, but we will not use it for programming a microcontroller.</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/Graphviz"><span class="image"><img src="../../images/dsls-and-language-workbenches/graphviz-logo.png" alt="graphviz logo" width="70"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/SQL"><span class="image"><img src="../../images/dsls-and-language-workbenches/sql-logo.png" alt="sql logo" width="80"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/HTML"><span class="image"><img src="../../images/dsls-and-language-workbenches/html-logo.png" alt="html logo" width="70"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/Maple_(software)"><span class="image"><img src="../../images/dsls-and-language-workbenches/maple-logo.png" alt="maple logo" width="100"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/AWK"><span class="image"><img src="../../images/dsls-and-language-workbenches/awk-logo.png" alt="awk logo" width="70"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/TeX"><span class="image"><img src="../../images/dsls-and-language-workbenches/tex-logo.png" alt="tex logo" width="70"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/MATLAB"><span class="image"><img src="../../images/dsls-and-language-workbenches/matlab-logo.png" alt="matlab logo" width="100"></span></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><a href="https://en.wikipedia.org/wiki/Logo_(programming_language)"><span class="image"><img src="../../images/dsls-and-language-workbenches/logo-logo.png" alt="logo logo" width="70"></span></a></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The power of DSLs is in that they capture the essence of a particular domain in a concise, efficient manner.
They focus on a specific domain and this makes them understandable to domain experts without requiring deep programming knowledge.
As a result, we achieve two important benefits of using DSLs.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Reuse of domain knowledge: DSLs embed domain-specific terms, structures, and processes, ensuring the knowledge is captured in a way that can be reused within the domain.</p>
</li>
<li>
<p>Make domain experts part of the development process: with DSLs, domain experts&#8201;&#8212;&#8201;those who best understand the problems and processes&#8201;&#8212;&#8201;can interact with the language directly, creating solutions that are robust and reflective of actual needs.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Thus, the software development process becomes more efficient, faster-to-market and bug-free.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="how-dsls-work-everything-is-a-model">How DSLs work: everything is a model</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The same as for software languages, a DSL consists of syntax and semantics.
However, as DSLs are meant to be usable and useful for domain experts with different technical background, DSLs can have multiple notations (concrete syntax) and multiple meanings (semantics).
For example, we might want to have both a textual notation (for the ease of editing and exchanging programs) and graphical notation (for the better overview and comprehension).
As for the semantics, we might want to generate executable source code, documentation, and test scenarios&#8201;&#8212;&#8201;all from the same DSL program.</p>
</div>
<div class="paragraph">
<p>To implement such an approach, we follow model-driven engineering (MDE) and put a model of the DSL in the center:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/dsls-and-language-workbenches/model-in-center-overview.png" alt="model in center overview">
</div>
</div>
<div class="paragraph">
<p>The domain model defines the structure of the DSL, its concepts and relationships between them.
Parsers, and editors offer various notations (visual and textual) and tools to create and edit models (DSL programs).
Translators and interpreters define semantics of the DSL by mapping its models to the executable code or other machine artifacts.</p>
</div>
<div class="paragraph">
<p>For example, here is a screenshot of the state machine DSL implemented in <a href="https://www.jetbrains.com/mps/">JetBrains MPS</a>:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/dsls-and-language-workbenches/mps-screenshot.png" alt="mps screenshot" width="800">
</div>
</div>
<div class="paragraph">
<p>Here on the left we see two representations of a state machine model: a textual and a graphical.
Both these representations are used to edit the actual (abstract) model behind.
And on the right is the Gherkin test scenario generated from the state machine model.
The following video demonstrates this example in action:</p>
</div>
<div class="videoblock">
<div class="content">
<iframe width="560" height="315" src="https://www.youtube.com/embed/6BCLuGeSisQ?rel=0" frameborder="0" allowfullscreen></iframe>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>DSLs are more than just specialized languages.
They are transformative tools that capture, express, and automate domain knowledge.
With DSLs, we can model and transform domain knowledge in ways that are scalable, reusable, and aligned with specific industry needs.
As the demand for efficient, specialized software grows, DSLs offer a powerful solution to bridge the gap between domain expertise and technology.</p>
</div>
<div class="paragraph">
<p>Do you think a DSL can be useful in your context?
We recommend to take these four considerations into account.</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Is there a real domain problem?
Do you see that the problem that you want to solve appears from time to time and can happen on different occasions?
Otherwise, if it is an isolated case then you might well solve it once using a general-purpose programming language.</p>
</li>
<li>
<p>Do you need subject matter experts (domain experts) to be closely involved in the development of the software system?
DSLs can incorporate subject matter experts, who are less knowledgable about the programming technology, in the development pipeline, leveraging their valuable domain knowledge in a consistent machine-ready form.</p>
</li>
<li>
<p>Do you see consistency in your domain structure and logic?
In other words, does your domain look like a language to you?
Then wrapping it into the form of an actual software language will capture this implicit knowledge and will free your mind for more interesting work.</p>
</li>
<li>
<p>Get <a href="https://www.f1re.nl">F1RE</a> involved.
At F1RE we specialize in the development and adoptation of DSLs for various types of industries and we will be happy to look together into your case!</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="further-reading">Further reading</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="https://en.wikipedia.org/wiki/Domain-specific_language">Wikipedia article on DSLs</a></p>
</li>
<li>
<p><a href="https://martinfowler.com/dsl.html">Martin Fowler&#8217;s guide on DSLs</a></p>
</li>
<li>
<p><a href="https://www.jetbrains.com/mps/concepts/domain-specific-languages/#:~:text=A%20Domain%20Specific%20Language%20is,from%20the%20field%20or%20domain.">JetBrains explanation of DSLs</a></p>
</li>
<li>
<p><a href="https://learn.microsoft.com/en-us/visualstudio/modeling/about-domain-specific-languages?view=vs-2022">Microsoft Learn about DSLs</a></p>
</li>
<li>
<p><a href="https://link.springer.com/book/10.1007/978-3-030-73758-0">Domain-Specific Languages in Practice: with JetBrains MPS (book)</a></p>
</li>
<li>
<p><a href="https://www.manning.com/books/building-user-friendly-dsls">Building User-Friendly DSLs (book)</a></p>
</li>
<li>
<p><a href="https://www.taylorfrancis.com/books/mono/10.1201/b21841/engineering-modeling-languages-benoit-combemale-robert-france-jean-marc-j%C3%A9z%C3%A9quel-didier-vojtisek-james-steel-bernhard-rumpe">Engineering Modeling Languages: Turning Domain Knowledge into Tools (book)</a></p>
</li>
</ul>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="DSL" /><summary type="html"><![CDATA[What are domain specific languages (DSLs) and language workbenches? Here is a small introduction on why, what and how of DSLs.]]></summary></entry><entry><title type="html">Implementing LionWeb in Rascal</title><link href="https://www.f1re.io/2024-07-08/lionweb-in-rascal" rel="alternate" type="text/html" title="Implementing LionWeb in Rascal" /><published>2024-07-08T00:00:00+00:00</published><updated>2024-07-08T00:00:00+00:00</updated><id>https://www.f1re.io/2024-07-08/lionweb-in-rascal</id><content type="html" xml:base="https://www.f1re.io/2024-07-08/lionweb-in-rascal"><![CDATA[<div class="paragraph">
<p><a href="https://lionweb.io">The LionWeb initiative</a> was started two years ago, to facilitate the interoperability between various language engineering tools and, in this way, to allow for the reuse of language engineering components and modeling tools.
Recently I have been working on the implementation of the LionWeb protocol in Rascal. <a href="https://www.rascal-mpl.org/">Rascal</a> is a meta-programming language that is used for the implementation of textual DSLs and for more generic use cases of syntax-based analysis and transformation of programming code.</p>
</div>
<div class="paragraph">
<p>Comparing to the tools already integrated with LionWeb, Rascal belongs to the traditional grammarware space.
In Rascal models are represented as abstract syntax trees and new types are defined using algebraic data types.
Furthermore, Rascal doesn’t support traditional OO concepts: there are no objects, only immutable values; no user defined sub-typing (i.e. inheritance); all models are pure trees, without explicit cross-referencing between their nodes.
To close this expressiveness gap, I used techniques introduced by the work 2017 by Tijs van der Storm on the <a href="https://github.com/cwi-swat/rascal-ecore">conversion between Ecore and Rascal</a>.</p>
</div>
<div class="paragraph">
<p>The current implementation of LionWeb in Rascal allows for importing LionWeb languages (M2) and models (M1) in Rascal. For example, we can now import an <code>Expressions</code> language created in MPS:
<span class="image"><img src="../../images/lionweb-in-rascal/expr-lang-in-MPS-3.png" alt="Expressions language defined in MPS"></span></p>
</div>
<div class="paragraph">
<p>&#8201;&#8212;&#8201;into Rascal, as a set of algebraic data types (ADT):
<span class="image"><img src="../../images/lionweb-in-rascal/expr-lang-in-rascal-2.png" alt="ADT of the Expressions language generated from the imported LionWeb language (M2)"></span></p>
</div>
<div class="paragraph">
<p>And using this imported <code>Expressions</code> language, we now can import an instance model created in MPS:
<span class="image"><img src="../../images/lionweb-in-rascal/expr-instance-in-MPS.png" alt="Model that instantiates the Expressions language in MPS" width="400"></span>&#8201;&#8212;&#8201;into Rascal, as an abstract syntax tree (AST):
<span class="image"><img src="../../images/lionweb-in-rascal/expr-instance-in-rascal.png" alt="AST of the model generated from the imported LionWeb model (M1)" width="400"></span></p>
</div>
<div class="paragraph">
<p>The implementation is available in the GitHub repository: <a href="https://github.com/UlyanaTikhonova/lionweb-rascal">https://github.com/UlyanaTikhonova/lionweb-rascal</a></p>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="LionWeb" /><category term="Rascal" /><summary type="html"><![CDATA[Recently I have been working on the implementation of the LionWeb protocol in Rascal.]]></summary></entry><entry><title type="html">Different ways of implementing enumerations in MPS and why they matter</title><link href="https://www.f1re.io/2024-05-03/implementing_enums" rel="alternate" type="text/html" title="Different ways of implementing enumerations in MPS and why they matter" /><published>2024-05-03T00:00:00+00:00</published><updated>2024-05-03T00:00:00+00:00</updated><id>https://www.f1re.io/2024-05-03/implementing_enums</id><content type="html" xml:base="https://www.f1re.io/2024-05-03/implementing_enums"><![CDATA[<div class="sect1">
<h2 id="implementing-enumerations">Implementing enumerations</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In MPS, enumerations can be implemented using different techniques.
The most obvious technique is using the <a href="https://www.jetbrains.com/help/mps/structure.html#enumerationds">Built-in Enumeration</a>.
However, there are two more ways of implementing enumerations: using Accessory models and using Abstract concepts.
Each implementation has its own advantages and disadvantages.
We go over a list of criteria and, for each implementation technique, discuss its advantages and disadvantages.</p>
</div>
<div class="paragraph">
<p>In this post, we make an enumeration for setting the visibility of variables, classes, or methods in Java.
The enumeration will contain: <code>Private</code>, <code>Protected</code>, and <code>Public</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For those wanting to see the end result: What&#8217;s implemented in this post <a href="https://github.com/f1re-nl/mps-enums">is available on GitHub</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-different-techniques">The different techniques</h2>
<div class="sectionbody">
<div class="paragraph">
<p>As mentioned before, enumerations can be implemented using the built-in Enumeration, Accessory models, and Abstract concepts.
In this section we show you how the enumeration can be implemented using each technique.
For each technique, we create a language.</p>
</div>
<div class="sect2">
<h3 id="using-the-built-in-enumeration">Using the built-in Enumeration</h3>
<div class="paragraph">
<p>Implementing enumerations using the MPS built-in Enumeration is one of the easiest to implement.</p>
</div>
<div class="paragraph">
<p>To do this, create a new language and call it <code>enumsEnum</code>.
Then, right-click on the structure model and select <span class="menuseq"><b class="menu">New</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Enumeration</b></span> and define the three visibility types.</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/CreateEnumConcept.png" alt="CreateEnumConcept" width="500"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/ImplementedEnumConcept.png" alt="ImplementedEnumConcept" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>That&#8217;s it!</p>
</div>
</div>
<div class="sect2">
<h3 id="using-the-accessory-model">Using the Accessory model</h3>
<div class="paragraph">
<p>Implementing enumerations through the accessory model can be done in the following way:</p>
</div>
<div class="paragraph">
<p>Create a new language and call it <code>enumsAccessory</code>.
Right-click on the structure model of the language, select <span class="menuseq"><b class="menu">New</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Concept</b></span>.
Give it a name (We call it <code>AccessoryVisibility</code>), extend <code>INamedConcept</code> and make it a root concept.</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/CreateNormalConcept.png" alt="CreateNormalConcept" width="500"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/ImplementedAccessoryConcept.png" alt="ImplementedAccessoryConcept" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Then, right-click on your language, select <span class="menuseq"><b class="menu">New</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Accessory model</b></span>.
In used languages of the accessory model, import your <code>enumsAccessory</code> language and, in Advanced, set <code>Do Not Generate</code> to <code>true</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/CreateAccessoryModel.png" alt="CreateAccessoryModel" width="333">
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ImportLanguage.png" alt="ImportLanguage" width="333">
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/DoNotGenerate.png" alt="DoNotGenerate" width="333">
</div>
</div>
<div class="paragraph">
<p>Finally, instantiate the concepts in the newly created accessory model to represent the enumeration members.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/NewAccessoryConcept.png" alt="NewAccessoryConcept" width="500">
</div>
</div>
</div>
<div class="sect2">
<h3 id="using-the-abstract-concept">Using the Abstract concept</h3>
<div class="paragraph">
<p>Create a new language and call it <code>enumsAbstract</code>.
Create a new concept, give it a name (We call it <code>AVisibility</code>) and make it abstract.</p>
</div>
<div class="paragraph">
<p>We then create new concepts that make the abstract <code>AVisibility</code> concept concrete.
To do this, we add new concepts for each visibility.
This is done in the following way:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p>Create a new concept.</p>
</li>
<li>
<p>Name it one of the visibility types (We show how to define <code>Private</code>)</p>
</li>
<li>
<p>Extend <code>AVisibility</code>.</p>
</li>
<li>
<p>Give it the corresponding alias</p>
</li>
</ol>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/ImplementedAbstractVisibility.png" alt="ImplementedAbstractVisibility" width="500"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/AbstractVisibilityPrivate.png" alt="AbstractVisibilityPrivate" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Now you can extend <code>AVisibility</code> for both <code>Protected</code> and <code>Public</code> as well.</p>
</div>
</div>
<div class="sect2">
<h3 id="summary">Summary</h3>
<div class="paragraph">
<p>In the end, if you followed along, you should have implemented the three types of visibility in three languages.
In each language, you will have either:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The abstract concept <code>AVisibility</code></p>
</li>
<li>
<p>The accessory concept <code>AccessoryVisibility</code></p>
</li>
<li>
<p>The built-in enumeration <code>EnumVisibility</code></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="evaluating-implementation-techniques">Evaluating implementation techniques</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Now, the question is: Why should we use different implementation techniques in the first place?
We can just use the built-in enumeration and be done, right?</p>
</div>
<div class="paragraph">
<p>Well, that&#8217;s where this section is for.
To evaluate the different implementation techniques, we go over the following criteria:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Extensibility</p>
</li>
<li>
<p>Flexibility</p>
</li>
<li>
<p>Working with it in code</p>
</li>
<li>
<p>Accessing information</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="extensibility">Extensibility</h3>
<div class="paragraph">
<p>Extensibility describes the ease with which the enumerations can be extended.</p>
</div>
<div class="paragraph">
<p>Let&#8217;s say a language user wants to add a fourth visibility to their own language: <code>Module</code>.
We show you how this can be done for each implementation technique.</p>
</div>
<div class="sect3">
<h4 id="built-in-enumeration">Built-in enumeration</h4>
<div class="paragraph">
<p>Using the built-in enumeration, it&#8217;s going to be tough.
Without changing the original language structure itself, this is not possible.</p>
</div>
</div>
<div class="sect3">
<h4 id="accessory-model">Accessory model</h4>
<div class="paragraph">
<p>To extend the visibility enumeration with the accessory model, the user can just add a new concept the same way the first three have been added: By creating a new instance in the accessory model of their new language.</p>
</div>
</div>
<div class="sect3">
<h4 id="abstract-concept">Abstract Concept</h4>
<div class="paragraph">
<p>Similarly, for the abstract concept, another concept can be created to extend the enumeration.
This concept&#8217;s name will then be <code>Module</code>, extending <code>AVisibility</code>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="flexibility">Flexibility</h3>
<div class="paragraph">
<p>Flexibility describes the ease with which the enumerations can be amended.
Let&#8217;s say we want to add more information to the different enumerations.
For example: we would like to specify which name the enumeration literal should get when generated.</p>
</div>
<div class="paragraph">
<p>To demonstrate the flexibility of each technique, we add additional information to the enumeration members by giving each member a technical name and a generation name.</p>
</div>
<div class="sect3">
<h4 id="built-in-enumeration-2">Built-in enumeration</h4>
<div class="paragraph">
<p>For the built-in enumeration, we can do this by adding attributes.</p>
</div>
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><input type="checkbox" data-item-complete="0"> First, we create a new language: <span class="menuseq"><b class="menu">New</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Language</b></span>.
Call it <code>enumAttributes</code>.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> In the new language, create a new concept and call it <code>AdditionalInfoAttribute</code>.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> To use this concept to store information as an attribute for another concept, we extend <code>NodeAttribute</code>.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> An error will pop up.
Click on <code>AdditionalInfoAttribute</code> and press <span class="keyseq"><kbd>Alt</kbd>+<kbd>Enter</kbd></span> / <span class="keyseq"><kbd>⌥</kbd>+<kbd>Enter</kbd></span>.
You can now click "Add Attribute Info".
This adds the necessary attribute info.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/AttributeError.png" alt="AttributeError" width="400">
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/AttributeQuickFix.png" alt="AttributeQuickFix" width="400">
</div>
</div>
<div class="paragraph">
<p>In the <code>@attribute info</code> section we add the following:</p>
</div>
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><input type="checkbox" data-item-complete="0"> For <em>multiple</em>, we select <code>false</code><br></p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> For <em>role</em>, we type <code>additionalInfo</code><br></p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> For <em>attributed concepts</em>, we import the <code>EnumerationMemberDeclaration</code> concept and select this concept here.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Doing so enables us to add attributes to members of a built-in enumeration.
Now, we add the information we want to store in this attribute as properties.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/AttributeConcept.png" alt="AttributeConcept" width="400">
</div>
</div>
<div class="paragraph">
<p>If we actually want to store information using this concept, we should be able to use this attribute for the intended enumeration member.</p>
</div>
<div class="paragraph">
<p>To do so, we create an intention in the <code>enumAttributes</code> language.
Let&#8217;s call this intention <code>AttachAdditionalInfo</code> and create it for the concept <code>EnumerationMemberDeclaration</code>.</p>
</div>
<div class="paragraph">
<p>As a description we write:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="n">description</span><span class="o">(</span><span class="n">node</span><span class="o">,</span> <span class="n">editorContext</span><span class="o">)-&gt;</span><span class="n">string</span> <span class="o">{</span>
  <span class="s">"Attach additional info"</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This intention executes the following code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="n">execute</span><span class="o">(</span><span class="n">node</span><span class="o">,</span> <span class="n">editorContext</span><span class="o">)-&gt;</span><span class="kt">void</span> <span class="o">{</span>
  <span class="n">node</span><span class="o">.</span><span class="nd">@additionalInfo</span><span class="o">.</span><span class="na">set</span> <span class="k">new</span><span class="o">(&lt;</span><span class="k">default</span><span class="o">&gt;);</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>This sets the <code>additionalInfo</code> attribute we&#8217;ve just created to the selected enumeration member.</p>
</div>
<div class="paragraph">
<p>To actually use this concept, we need to create the editor for this attribute.</p>
</div>
<div class="paragraph">
<p>In the editor we add a vertical collection.
In the vertical collection we add 2 horizontal collections for setting the respective properties.
After adding the horizontal collections, we add a new cell in the vertical collection again and here we add <code>attributed node</code> by pressing <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Space</kbd></span> / <span class="keyseq"><kbd>^</kbd>+<kbd>Space</kbd></span>.
It should look like this:</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/EditorAttribute.png" alt="EditorAttribute" width="500"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/AttributeEditor.png" alt="AttributeEditor" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Now, go to the <code>Module Properties</code> of your original language.
In the dependencies section, add the newly created language (<code>enumAttributes</code>).
Now we can use the intention to add an attribute to the enumeration member:</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If the intention does not pop up, use <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>R</kbd></span> / <span class="keyseq"><kbd>^</kbd>+<kbd>R</kbd></span> to import the <code>AttachAdditionalInfo</code> intention.</p>
</div>
</td>
</tr>
</table>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/EnumIntention.png" alt="EnumIntention" width="500"></span></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/enums-implementations/EnumAddedAttribute.png" alt="EnumAddedAttribute" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="accessory-model-2">Accessory model</h4>
<div class="paragraph">
<p>For the accessory model, we add properties.
To add the technical name and the generation name, we simply add the properties to the <code>AccessoryVisibility</code> concept.</p>
</div>
<div class="paragraph">
<p><code>technicalName : string</code></p>
</div>
<div class="paragraph">
<p><code>generationName : string</code></p>
</div>
<div class="paragraph">
<p>Now, for each concept in the accessory model, we can enter its technical name and generation name.</p>
</div>
</div>
<div class="sect3">
<h4 id="abstract-concept-2">Abstract Concept</h4>
<div class="paragraph">
<p>For the abstract concepts, we define behaviors.
Go to the abstract concept <code>AVisiblity</code>, click on the <code>+</code> on the bottom left, <span class="menuseq"><b class="menu">Behavior</b>&#160;<i class="fa fa-angle-right caret"></i> <b class="menuitem">Concept Behavior</b></span>.
Here, we can define two <code>public virtual abstract string</code> methods called <code>technicalName()</code> and <code>generationName()</code>.</p>
</div>
<div class="paragraph">
<p>Then, for each concrete concept, we can override these methods (by using <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>O</kbd></span> / <span class="keyseq"><kbd>^</kbd>+<kbd>O</kbd></span>) to set their respective technical names and generation names.
So, when we create a new behavior for the concrete <code>Public</code> concept we would write here:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="n">virtual</span> <span class="n">string</span> <span class="nf">technicalName</span><span class="o">()</span>
  <span class="n">overrides</span> <span class="nc">AVisibility</span><span class="o">.</span><span class="na">technicalName</span> <span class="o">{</span>
  <span class="s">"public"</span><span class="o">;</span>
<span class="o">}</span>

<span class="kd">public</span> <span class="n">virtual</span> <span class="n">string</span> <span class="nf">generationName</span><span class="o">()</span>
  <span class="n">overrides</span> <span class="nc">AVisibility</span><span class="o">.</span><span class="na">generationName</span> <span class="o">{</span>
  <span class="s">"openbaar"</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="sect4">
<h5 id="advantages-and-disadvantages">Advantages and disadvantages</h5>
<div class="paragraph">
<p>We have gone over a lot of information in this section.
To provide an overview, we discuss the advantages and disadvantages here.</p>
</div>
<div class="paragraph">
<p>During the implementation of the different techniques, you might have wondered why Abstract concepts do not use properties as well, just like Accessory models.</p>
</div>
<div class="paragraph">
<p>Using properties is a quick way to store additional information for an instantiated concept.
However, these values will be hard-coded and leave no room for values that need to be calculated.
Additionally, these properties need to be redefined each time the concept is instantiated.
This goes against the principle of an enumeration, which has the same value everywhere.
Behaviors provide flexibility and allow you to define values that are consistent among each literal instance.
However, when we need to define behaviors for every concrete concept, we are left with a bunch of behaviors, making our project cluttered.</p>
</div>
<div class="paragraph">
<p>Using an attribute in the built-in enumeration is both difficult to implement and demand the user to provide hard-coded information.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="working-with-it-in-code">Working with it in code</h3>
<div class="paragraph">
<p>Now, the enumeration itself does not mean anything yet: We want the different enumeration members to actually say something about the classes/methods/etc. that use this enumeration.
For example, if a class is <code>public</code>, we want it to be visible to every class.
For <code>protected</code>, we only want it to be visible to the same class.
For <code>private</code>, we don&#8217;t want it to be visible at all.</p>
</div>
<div class="paragraph">
<p>We define this logic by writing code using a <code>Behavior</code>.</p>
</div>
<div class="paragraph">
<p>For each concept, let&#8217;s create a new language (Including a sandbox.
We are going to use this in the next section).
Call it <code>{implementation technique}</code> + <code>Behavior</code> (So the language for <code>AccessoryVisibility</code> is <code>AccessoryBehavior</code>) and set the language in which you have implemented the enumeration as a dependency.</p>
</div>
<div class="paragraph">
<p>In the structure aspect of your new language, create a new concept for which we want to set the visibility. To stay consistent with the example throughout this post, we will use operations. Call it <code>Operation + {the implementation technique}</code> (for example <code>OperationEnum</code> or <code>OperationAccessory</code>), extend <code>BaseConcept</code>, don&#8217;t make it root, and implement <code>INamedConcept</code>.</p>
</div>
<div class="paragraph">
<p>To instantiate multiple <code>Operation</code> nodes, we create a new concept that stores these operations.
In Java, we have a <code>Class</code> which can store multiple <code>Methods</code>. Similarly, we will have a concept <code>Container</code> that stores the <code>Operation</code> nodes.
Create a new root concept and call it <code>Container</code>.
In <code>Container</code> set the corresponding <code>Operation</code> node as a child with a cardinality of <code>[0..n]</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ContainerEnum.png" alt="ContainerEnum" width="375">
</div>
</div>
<div class="paragraph">
<p>Now, we can create the <code>Behavior</code> for each <code>Operation</code> concept we have created.
Using this behavior, we demonstrate how to define the logic for the enumerations.</p>
</div>
<div class="sect3">
<h4 id="built-in-enumeration-3">Built-in enumeration</h4>
<div class="paragraph">
<p>In the <code>OperationEnum</code> behavior, we create an enum switch.
The enum switch accesses the visibility of this concept and compares it to the visibility of the other concept should this be needed.</p>
</div>
<div class="paragraph">
<p>As mentioned before, we want <code>private</code> to not be visible, <code>protected</code> only when the classes are the same, and <code>public</code> always.
Therefore, we write the following code:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isVisibleEnum</span><span class="o">(</span><span class="n">node</span><span class="o">&lt;</span><span class="nc">OperationEnum</span><span class="o">&gt;</span> <span class="n">other</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="kd">enum</span> <span class="nf">switch</span> <span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">enumVisibility</span><span class="o">)</span> <span class="o">{</span>
        <span class="kd">private</span> <span class="o">-&gt;</span> <span class="kc">false</span><span class="o">;</span>
        <span class="kd">protected</span> <span class="o">-&gt;</span> <span class="n">other</span><span class="o">.</span><span class="na">model</span> <span class="o">:</span><span class="nl">eq:</span> <span class="k">this</span><span class="o">.</span><span class="na">model</span><span class="o">;</span>
        <span class="kd">public</span> <span class="o">-&gt;</span> <span class="kc">true</span><span class="o">;</span>
    <span class="o">};</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="accessory-model-3">Accessory model</h4>
<div class="paragraph">
<p>Similar to the enum concept switch, we can check in the <code>OperationAccessory</code> behavior if the other node is either <code>public</code>, <code>private</code> or <code>protected</code>.
However, for the accessory model we use if-statements.</p>
</div>
<div class="paragraph">
<p>To access the nodes from the accessory model, we access the pointer of the <code>AccessoryVisibility</code> concept.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If you can not find the <code>private</code>, <code>protected</code>, and <code>public</code> concepts, import them using <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>R</kbd></span> / <span class="keyseq"><kbd>^</kbd>+<kbd>R</kbd></span>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Using this pointer, we compare whether the pointer points to <code>private</code>, <code>protected</code>, or <code>public</code> and write the corresponding code.
The code looks like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isVisibleAccessory</span><span class="o">(</span><span class="n">node</span><span class="o">&lt;</span><span class="nc">OperationAccessory</span><span class="o">&gt;</span> <span class="n">other</span><span class="o">)</span> <span class="o">{</span>
  <span class="n">node</span><span class="o">-</span><span class="n">ptr</span><span class="o">&lt;</span><span class="nc">AccessoryVisibility</span><span class="o">&gt;</span> <span class="n">visibility</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">accessoryVisibility</span><span class="o">.</span><span class="na">pointer</span><span class="o">;</span>
  <span class="k">if</span> <span class="o">(</span><span class="n">visibility</span> <span class="o">:</span><span class="nl">eq:</span> <span class="n">node</span><span class="o">-</span><span class="n">ptr</span><span class="o">/</span><span class="nc">Private</span><span class="o">/)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
  <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">visibility</span> <span class="o">:</span><span class="nl">eq:</span> <span class="n">node</span><span class="o">-</span><span class="n">ptr</span><span class="o">/</span><span class="nc">Protected</span><span class="o">/)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">other</span><span class="o">.</span><span class="na">model</span> <span class="o">:</span><span class="nl">eq:</span> <span class="k">this</span><span class="o">.</span><span class="na">model</span><span class="o">;</span>
  <span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">visibility</span> <span class="o">:</span><span class="nl">eq:</span> <span class="n">node</span><span class="o">-</span><span class="n">ptr</span><span class="o">/</span><span class="nc">Public</span><span class="o">/)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
  <span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
    <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
  <span class="o">}</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="abstract-concept-3">Abstract Concept</h4>
<div class="paragraph">
<p>Using the <code>OperationAbstract</code> behavior, we can define the logic in two ways:
Through a concept switch or by defining behaviors for each corresponding concrete concept.</p>
</div>
<div class="sect4">
<h5 id="through-a-concept-switch">Through a concept switch</h5>
<div class="paragraph">
<p>This method is similar to the enum switch we have seen in the built-in enumeration section.
Instead, we use a switch statement for concepts:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isVisibleConceptA</span><span class="o">(</span><span class="n">node</span><span class="o">&lt;</span><span class="nc">OperationAbstract</span><span class="o">&gt;</span> <span class="n">other</span><span class="o">)</span> <span class="o">{</span>
    <span class="n">concept</span> <span class="nf">switch</span> <span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">abstractVisibility</span><span class="o">.</span><span class="na">concept</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">subconcept</span> <span class="n">of</span> <span class="nc">PrivateVisibility</span> <span class="o">:</span>
            <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
        <span class="n">subconcept</span> <span class="n">of</span> <span class="nc">ProtectedVisibility</span> <span class="o">:</span>
            <span class="k">return</span> <span class="n">other</span><span class="o">.</span><span class="na">model</span> <span class="o">:</span><span class="nl">eq:</span> <span class="k">this</span><span class="o">.</span><span class="na">model</span><span class="o">;</span>
        <span class="n">subconcept</span> <span class="n">of</span> <span class="nc">PublicVisibility</span> <span class="o">:</span>
            <span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
        <span class="k">default</span> <span class="o">:</span>
            <span class="o">&lt;</span><span class="n">no</span> <span class="n">defaultBlock</span><span class="o">&gt;</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="define-behaviors">Define behaviors</h5>
<div class="paragraph">
<p>A different technique would be to define a <code>virtual abstract boolean</code> method in the behavior of the abstract concept <code>AVisibility</code>.
We can then define a behavior for each concrete concept to override this abstract method.</p>
</div>
<div class="paragraph">
<p><code>public virtual abstract boolean isVisible(node&lt;OperationAbstract&gt; other);</code></p>
</div>
<div class="paragraph">
<p>For the <code>Private</code> visibility concept that extends the abstract visibility concept, we should then override this method in the following way:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="n">virtual</span> <span class="kt">boolean</span> <span class="nf">isVisible</span><span class="o">(</span><span class="n">node</span><span class="o">&lt;</span><span class="nc">OperationAbstract</span><span class="o">&gt;</span> <span class="n">other</span><span class="o">)</span>
  <span class="n">overrides</span> <span class="nc">AVisibility</span><span class="o">.</span><span class="na">isVisible</span> <span class="o">{</span>
  <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We can now call this method in the <code>OperationAbstract</code> behavior:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isVisibleConceptB</span><span class="o">(</span><span class="n">node</span><span class="o">&lt;</span><span class="nc">OperationAbstract</span><span class="o">&gt;</span> <span class="n">other</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">abstractVisibility</span><span class="o">.</span><span class="na">isVisible</span><span class="o">(</span><span class="n">other</span><span class="o">);</span>
<span class="o">}</span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="advantages-and-disadvantages-2">Advantages and disadvantages</h4>
<div class="paragraph">
<p>Using switches to determine the return value is very concise.
However, extending these switches is difficult without putting in a lot of effort.</p>
</div>
<div class="paragraph">
<p>Instead, the usage of behaviors solve this problem.
This is less concise but makes the language able to be extended.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="accessing-information">Accessing information</h3>
<div class="paragraph">
<p>Lastly, we want to be able to access the information from the concepts.
We show how this is done by creating a generator for each concept.
First we instantiate the <code>Container</code> instance for each implementation technique, create the root mapping rule, and eventually create the reduction rules in which we access the stored information.</p>
</div>
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><input type="checkbox" data-item-complete="0"> Create the editor for the <code>Container</code> concept and instantiate it in the sandbox of your corresponding <code>&#8230;&#8203;Behavior</code> language.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> Go to the generator of your language and import the <code>jetbrains.mps.core.xml</code> language.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> In the root mapping rule select <code>Container</code> and create a new root mapping template for <code>xml file</code>.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/RootMappingRule.png" alt="RootMappingRule" width="375">
</div>
</div>
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><input type="checkbox" data-item-complete="0"> In the root mapping rule, we first create an XML base element.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> Here, we type "class". Add a <code>name</code> attribute and add a property macro to access <code>node.name</code>.</p>
</li>
<li>
<p><input type="checkbox" data-item-complete="0"> Go inside the element and add a <code>$COPY_SRCL$</code> node macro for the operations stored in the container.</p>
</li>
</ul>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ContainerRootMapping.png" alt="ContainerRootMapping" width="375">
</div>
</div>
<div class="ulist checklist">
<ul class="checklist">
<li>
<p><i class="fa fa-square-o"></i> Then, create a new reduction rule for the concept stored in <code>Container</code>.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Create an <code>&lt;in-line template&gt;</code>, instantiate a new <code>XML element</code>, and type "method".</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Add an attribute called "name" and add a property macro on this attribute to retrieve the node&#8217;s name.</p>
</li>
<li>
<p><i class="fa fa-square-o"></i> Add an attribute called "visibility" and add a property macro on this attribute as well.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For the abstract concept, it should look like this:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/AbstractReductionRule.png" alt="AbstractReductionRule" width="375">
</div>
</div>
<div class="paragraph">
<p>In the respective inspectors for the visibility property macro, we now want to retrieve the generation names we have set in either the behaviors, attributes or properties.</p>
</div>
<div class="sect3">
<h4 id="built-in-enumeration-4">Built-in enumeration</h4>
<div class="paragraph">
<p>You will notice that when trying to retrieve the generation name stored in the <code>enumVisibility</code> concept, we can not access this node&#8217;s <code>AdditionalInfoAttribute</code>.
We can access this node, but we need functionality that helps us do this.
Go to the <code>OperationEnum</code> behavior and create the following method:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="java"><span class="kd">public</span> <span class="n">node</span><span class="o">&lt;</span><span class="nc">EnumerationMemberDeclaration</span><span class="o">&gt;</span> <span class="nf">getEnumerationMemberDeclaration</span><span class="o">()</span> <span class="o">{</span>
    <span class="n">node</span><span class="o">&lt;</span><span class="nc">EnumerationMemberDeclaration</span><span class="o">&gt;</span> <span class="n">enumMember</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">enumVisibility</span><span class="o">.</span><span class="na">getSourceNode</span><span class="o">().</span><span class="na">resolve</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">model</span><span class="o">/.</span><span class="na">getRepository</span><span class="o">())</span> <span class="n">as</span> <span class="nc">EnumerationMemberDeclaration</span><span class="o">;</span>
    <span class="k">return</span> <span class="n">enumMember</span><span class="o">;</span>
<span class="o">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>We can now invoke this method in the inspector of the property macro by typing <code>node.getEnumerationMemberDeclaration()</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>When using this in your own project, be sure to put this method in a more central place. This way this method can be called from more places than just <code>OperationEnum</code>!</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Using this method, we can access the <code>attributeInfo</code> of the built-in enumeration (If this is not accessible, import <code>AdditionalInfoAttribute</code> using <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>R</kbd></span> / <span class="keyseq"><kbd>^</kbd>+<kbd>R</kbd></span>)
In the inspector of <code>visibility</code> in <code>OperationEnum</code>, type: <code>node.getEnumerationMemberDeclaration().@additionalInfo.generationName;</code></p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ReductionInspectorEnum.png" alt="ReductionInspectorEnum" width="375">
</div>
</div>
</div>
<div class="sect3">
<h4 id="accessory-model-4">Accessory model</h4>
<div class="paragraph">
<p>For the accessory model, we can simply access the property of the <code>AccessoryVisibility</code> concept. We first get the <code>AccessoryVisibility</code> concept from <code>OperationAccessory</code> and then get it&#8217;s generation name:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ReductionInspectorAccessory.png" alt="ReductionInspectorAccessory" width="375">
</div>
</div>
</div>
<div class="sect3">
<h4 id="abstract-concept-4">Abstract concept</h4>
<div class="paragraph">
<p>For the abstract concept, we call the method in the concrete concept that overrides the <code>generationName()</code> method. We do this in the following way:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/ReductionInspectorAbstract.png" alt="ReductionInspectorAbstract" width="375">
</div>
</div>
</div>
<div class="sect3">
<h4 id="using-the-generator">Using the generator</h4>
<div class="paragraph">
<p>Now, if we go back to the sandbox in which we instantiated <code>Container</code>, we can press <span class="keyseq"><kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Shft</kbd>+<kbd>F9</kbd></span> to see a preview of the generated text. Using any enumeration, it should look like this:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/GenInputXML.png" alt="GenInputXML" width="375">
</div>
</div>
<div class="imageblock">
<div class="content">
<img src="../../images/enums-implementations/GenOutputXML.png" alt="GenOutputXML" width="375">
</div>
</div>
<div class="paragraph">
<p>That&#8217;s it! &#x1F604;</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="conclusion">Conclusion</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In this post, we have looked at three different implementation techniques: The built-in enumerations, enumerations using the abstract concept, and enumerations using the accessory model.
Now the question is: which technique should you use?</p>
</div>
<div class="paragraph">
<p>As most things in this world: <em>It depends</em>.
This all depends on your use case.</p>
</div>
<div class="paragraph">
<p>Using the built-in enumeration is very easy, but very often bites in the long run&#8201;&#8212;&#8201;languages tend to evolve and split up, then enums get messy.
Also, built-in enums are hard to migrate.
Accessories are a good compromise between additional effort and flexibility.
Abstract has the most flexibility, but also takes the most effort.</p>
</div>
<div class="paragraph">
<p>Our advice: Outside corner cases, don&#8217;t use built-in. Choose between accessories and abstract according to your needs, these two are also easier to migrate between.</p>
</div>
<div class="paragraph">
<p>Additionally, to help you figure out which technique you should use, we highlight the advantages and disadvantages in the following table.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top"></th>
<th class="tableblock halign-left valign-top">Built-in enum</th>
<th class="tableblock halign-left valign-top">Accessory model</th>
<th class="tableblock halign-left valign-top">Abstract concept</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Extensibility</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x274C; Can&#8217;t be extended unless the original language is modified</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to extend through a new instance of the accessory concept.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to extend through a new concrete concept.</p>
<p class="tableblock">&#x274C; Requires a bit more effort than the accessory model</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Flexibility</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Consistent values among instances.</p>
<p class="tableblock">&#x274C; Difficult to implement.</p>
<p class="tableblock">&#x274C; Values are hardcoded.</p>
<p class="tableblock">&#x274C; Does not allow values to be calculated.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to implement.</p>
<p class="tableblock">&#x2705; Values are consistent among each instance.</p>
<p class="tableblock">&#x274C; Values are hardcoded.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to implement.</p>
<p class="tableblock">&#x2705; Support multiple methods for adding additional information.</p>
<p class="tableblock">&#x274C; Too many behaviors clutter the project.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Working with it in code</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Concise using the enum switch.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x274C; Code is hard to read.</p>
<p class="tableblock">&#x274C; Not extensible without effort.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Concise using the concept switch.</p>
<p class="tableblock">&#x2705; Can be extended using behaviors.</p>
<p class="tableblock">&#x274C; Too many behaviors if every enumeration literal needs a behavior.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>Accessing information</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x274C; Requires effort to access the node with the information.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to access information using properties</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">&#x2705; Easy to access information using behaviors</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Thanks for reading this post and have fun implementing!</p>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="JetBrains MPS" /><summary type="html"><![CDATA[We go over the different techniques for implementing enumerations in MPS and go over the advantages and disadvantages.]]></summary></entry><entry><title type="html">🚀 Unlocking the Power of Domain-Specific Languages in Tax Law 🚀</title><link href="https://www.f1re.io/2024-05-02/why-use-a-dsl-pt1" rel="alternate" type="text/html" title="🚀 Unlocking the Power of Domain-Specific Languages in Tax Law 🚀" /><published>2024-05-02T00:00:00+00:00</published><updated>2024-05-02T00:00:00+00:00</updated><id>https://www.f1re.io/2024-05-02/why-use-a-dsl-pt1</id><content type="html" xml:base="https://www.f1re.io/2024-05-02/why-use-a-dsl-pt1"><![CDATA[<div class="paragraph">
<p>Navigating the complex world of tax law can be a daunting task for even the most seasoned Subject Matter Expert. The details, regulations, and specific terminologies require precision and understanding that generic tools often fail to provide. This is where the magic of Domain-Specific Languages (DSLs) comes into play.</p>
</div>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>🔍 𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲: Imagine tax lawyers wrestling with generic spreadsheets filled with data, formulas, and references. Their frustration is understandable as they navigate through mostly unreadable text, trying to decode and apply tax laws accurately.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/why-use-a-DSL/tax1.jpg" alt="tax1" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>💡 𝗧𝗵𝗲 𝗦𝗼𝗹𝘂𝘁𝗶𝗼𝗻: DSLs, designed with the specific needs of tax professionals in mind. The collaboration between the SMEs and DSL experts allows for the development of a language specifically tailored to the needs of the experts' workflow, transforming frustration into efficiency.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/why-use-a-DSL/tax2.jpg" alt="tax2" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/why-use-a-DSL/tax3.jpg" alt="tax3" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<table class="tableblock frame-none grid-none stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p>🎉 𝗧𝗵𝗲 𝗢𝘂𝘁𝗰𝗼𝗺𝗲: With these new DSLs, tax lawyers now find themselves empowered in front of their computers. The once complex spreadsheets have transformed into user-friendly interfaces, where tax laws and regulations are seamlessly integrated into their workflow. The details of tax law are no longer barriers but tools at their fingertips.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div class="content"><div class="paragraph">
<p><span class="image"><img src="../../images/why-use-a-DSL/tax4.jpg" alt="tax4" width="500"></span></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="sect1">
<h2 id="why-dsls">🌟 Why DSLs?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>𝗣𝗿𝗲𝗰𝗶𝘀𝗶𝗼𝗻: Tailored to specific domains, ensuring accuracy in tasks.</p>
</div>
<div class="paragraph">
<p>𝗘𝗳𝗳𝗶𝗰𝗶𝗲𝗻𝗰𝘆: Streamlines processes, reducing time spent on complex analyses.</p>
</div>
<div class="paragraph">
<p>𝗔𝗰𝗰𝗲𝘀𝘀𝗶𝗯𝗶𝗹𝗶𝘁𝘆: Makes complex regulations understandable, enhancing decision-making.</p>
</div>
<div class="paragraph">
<p>The adoption of DSLs in specialized fields is not just an innovation; it&#8217;s a necessity. For professionals and visionary teams alike, it can be a game-changer, transforming challenges into opportunities.</p>
</div>
</div>
</div>]]></content><author><name>{&quot;same_as&quot;=&gt;[]}</name></author><category term="DSL" /><summary type="html"><![CDATA[In this example we explain how a DSL could be of value in the domain of Tax Law]]></summary></entry></feed>