Jekyll2022-09-05T13:39:38+00:00https://heinecke.com/blog/feed.xmlHasko Heinecke, Enterprise IT ArchitectVarious things that I find interesting, such as programming, IT architecture and some hobbies.Upgrading Jekyll2021-01-19T00:00:00+00:002021-01-19T00:00:00+00:00https://heinecke.com/blog/2021/01/19/upgrading-jekyll<p>It is always surprising how long it takes to properly implement a small change. Today, I upgraded this website from Jekyll 3.x to 4.x. It is a small upgrade made only slightly more complicated by me finally adding tags to the articles (see at the top of this article), with a link to a proper tag page. Everything worked extremely smoothly, so there is no reason to complain. Nevertheless, it took me about two hours to get it all working to my satisfaction, including the automated generation of the site.</p>
<p>Morale of the story: It always takes longer than you think, even if you take this morale into account.</p>
<p>But the story has a happy end, so what can I say. š</p>It is always surprising how long it takes to properly implement a small change. Today, I upgraded this website from Jekyll 3.x to 4.x. It is a small upgrade made only slightly more complicated by me finally adding tags to the articles (see at the top of this article), with a link to a proper tag page. Everything worked extremely smoothly, so there is no reason to complain. Nevertheless, it took me about two hours to get it all working to my satisfaction, including the automated generation of the site.Holocracy on Rails, part 22021-01-17T00:00:00+00:002021-01-17T00:00:00+00:00https://heinecke.com/blog/2021/01/17/holocracy-02<p>In the <a href="/blog/2021/01/10/holocracy-on-rails.html">previous part of the series</a>, I have shown how to quickly create a set of models, controllers, and views, plus some other useful stuff, to implement a tool to support the Holocracy method of running an organization. However, the tool was not much more than a database browser at this time, which is neat enough for ten minutes of work, but letās go a little further.</p>
<h2 id="filling-roles">Filling roles</h2>
<p>For one thing, I have made a conceptual mistake. I have constrained the reference from a Role to a Person so that it cannot be empty (or <code class="language-plaintext highlighter-rouge">null</code>). But that does not reflect reality very well. In an organization we often have the situation that a role is defined but it is not filled by a person. Of course, we want to fill it and sometimes there will be someone filling it ad interim, but still I feel I should not exclude the possibility that a specific role is unfilled. So I will remove the not-null constraint from the Person reference in Role. I will do this as a database migration, so that the change is formulated in code and can be reproduced on any production database that I might have.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bin/rails generate migration RemoveNotNullConstraintFromPersonInRoles
Running via Spring preloader <span class="k">in </span>process 888
invoke active_record
create db/migrate/20210108172101_remove_not_null_constraint_from_person_in_roles.rb
</code></pre></div></div>
<p>The migration code looks like this. I have already inserted line 3 where I tell Rails to set the null constraint to true.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">RemoveNotNullConstraintFromPersonInRoles</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">6.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">change_column_null</span> <span class="ss">:roles</span><span class="p">,</span> <span class="ss">:person_id</span><span class="p">,</span> <span class="kp">true</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails db:migrate
<span class="o">==</span> 20210108172101 RemoveNotNullConstraintFromPersonInRoles: migrating <span class="o">=========</span>
<span class="nt">--</span> change_column_null<span class="o">(</span>:roles, :person_id, <span class="nb">true</span><span class="o">)</span>
-> 0.0776s
<span class="o">==</span> 20210108172101 RemoveNotNullConstraintFromPersonInRoles: migrated <span class="o">(</span>0.0777s<span class="o">)</span>
</code></pre></div></div>
<p>Running the migration yields the new database schema but I also need to adapt the model by marking the relation optional, and by adjusting the validation so that the UI will not complain about missing people.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Role</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">belongs_to</span> <span class="ss">:person</span><span class="p">,</span> <span class="ss">optional: </span><span class="kp">true</span>
<span class="n">belongs_to</span> <span class="ss">:circle</span>
<span class="n">validates</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="n">validates</span> <span class="ss">:circle</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Next, I will change the input field in the Role for to a selection box, so that the user can choose from the people in known to the tool. Rails has a helper function for this common requirement, called <code class="language-plaintext highlighter-rouge">collection_select</code>. Spot it in the code below.</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="n">role</span><span class="p">,</span> <span class="ss">local: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
...
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:person_id</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">collection_select</span> <span class="ss">:person_id</span><span class="p">,</span> <span class="no">Person</span><span class="p">.</span><span class="nf">order</span><span class="p">(</span><span class="ss">:name</span><span class="p">),</span> <span class="ss">:id</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="p">{</span> <span class="ss">include_blank: </span><span class="kp">true</span> <span class="p">}</span> <span class="cp">%></span>
<span class="nt"></div></span>
...
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre></div></div>
<p>What it means is: Create an HTML <code class="language-plaintext highlighter-rouge">select</code> element to fill the <code class="language-plaintext highlighter-rouge">person_id</code> attribute. Use the list of all Persons in the database, ordered by their name, as options. Use the <code class="language-plaintext highlighter-rouge">id</code> attribute of the selected person but display the <code class="language-plaintext highlighter-rouge">name</code> attribute to the user. Include a blank selection to represent that no person currently fills this role. Railsā helpers save a lot of time.</p>
<p>## Dependent Resources</p>
<p>Up to now, I have treated Roles as if they were completely independent entities. But in reality, every Role belongs to one circle. It does not exist outside its circle, and there should be no way to create roles that do not belong to a pre-existing circle. For this, Rails has the concept of <em>dependent resources</em>. Letās have a look at the file <code class="language-plaintext highlighter-rouge">holo/config/routes.rb</code> that was generated along with our scaffolds:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span>
<span class="n">resources</span> <span class="ss">:roles</span>
<span class="n">resources</span> <span class="ss">:circles</span>
<span class="n">resources</span> <span class="ss">:people</span>
<span class="c1"># For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">resources</code> keyword means that Rails will route the usual REST requests to the corresponding controllers, e.g. <code class="language-plaintext highlighter-rouge">GET /circles</code> will be routed to the the <code class="language-plaintext highlighter-rouge">index</code> method in the <code class="language-plaintext highlighter-rouge">CircleController</code> class. To make the roles dependend on circles, I will emply a little Rails syntax:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span>
<span class="n">resources</span> <span class="ss">:circles</span> <span class="k">do</span>
<span class="n">resources</span> <span class="ss">:roles</span><span class="p">,</span> <span class="ss">shallow: </span><span class="kp">true</span>
<span class="k">end</span>
<span class="n">resources</span> <span class="ss">:people</span>
<span class="c1"># For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html</span>
<span class="k">end</span>
</code></pre></div></div>
<p>By putting the roles resources <em>inside</em> the circles resource, we cannot simply call <code class="language-plaintext highlighter-rouge">GET /roles/new</code> anymore. We must call <code class="language-plaintext highlighter-rouge">GET /circles/:id/roles/new</code> where <code class="language-plaintext highlighter-rouge">:id</code> is the ID of a specific circle. The phrase <code class="language-plaintext highlighter-rouge">shallow: true</code> means that this only happens for listing all roles (the index method in the controller) and for creating new resources within the scope of that circle. Showing and editing existing roles will not require the long URL because they do not break the link between a role and the circle it belongs to. This is not very important. I just like to do it because it avoids unnecessarily long URLs.</p>
<p>Next, we must adapt the Role controller and its views to reflect the change. The first part of the <code class="language-plaintext highlighter-rouge">RolesController</code> class currently looks like this, all generated code:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">RolesController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="n">before_action</span> <span class="ss">:set_role</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">,</span> <span class="ss">:edit</span><span class="p">,</span> <span class="ss">:update</span><span class="p">,</span> <span class="ss">:destroy</span><span class="p">]</span>
<span class="c1"># GET /roles</span>
<span class="c1"># GET /roles.json</span>
<span class="k">def</span> <span class="nf">index</span>
<span class="vi">@roles</span> <span class="o">=</span> <span class="no">Role</span><span class="p">.</span><span class="nf">all</span>
<span class="k">end</span>
<span class="o">...</span>
</code></pre></div></div>
<p>Now I only want to show the roles that belong to the current circle. The ID of the circle is automatically passed in the request parameters, so I just have to replace <code class="language-plaintext highlighter-rouge">Role.all</code> with an appropriate query:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span>
<span class="c1"># GET /circle/:circle_id/roles</span>
<span class="c1"># GET /circle/:circle_id/roles.json</span>
<span class="k">def</span> <span class="nf">index</span>
<span class="vi">@circle</span> <span class="o">=</span> <span class="no">Circle</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:circle_id</span><span class="p">])</span>
<span class="vi">@roles</span> <span class="o">=</span> <span class="no">Role</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">circle: </span><span class="vi">@circle</span><span class="p">)</span>
<span class="k">end</span>
<span class="o">...</span>
</code></pre></div></div>
<p>Note that I have also adapted the comment to reflect the new routes. This is just for my information.</p>
<p>Now I will change the index view in <code class="language-plaintext highlighter-rouge">holo/app/views/roles/index.html.erb</code> so the the link to create a new role passes the current circle ID. The old line looked like this:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'New Role'</span><span class="p">,</span> <span class="n">new_role_path</span> <span class="cp">%></span>
</code></pre></div></div>
<p>But now I have changed it to:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'New Role'</span><span class="p">,</span> <span class="n">new_circle_role_path</span><span class="p">(</span><span class="vi">@circle</span><span class="p">)</span> <span class="cp">%></span>
</code></pre></div></div>
<p>Here, I am using another helper that creates a route for my dependent resource. If you try and hover over the link, your browser will show the generated URL:</p>
<p><img src="/j/assets/series/holo-rails/roles-01.png" alt="A dependent resource" class="centered" /></p>
<p>Now, I need to adjust the <code class="language-plaintext highlighter-rouge">new</code> method in the <code class="language-plaintext highlighter-rouge">RolesController</code>. Here is the generated code:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span>
<span class="c1"># GET /roles/new</span>
<span class="k">def</span> <span class="nf">new</span>
<span class="vi">@role</span> <span class="o">=</span> <span class="no">Role</span><span class="p">.</span><span class="nf">new</span>
<span class="k">end</span>
<span class="o">...</span>
</code></pre></div></div>
<p>I will adjust the comment to reflect the new route, and I need to extract the circle from the URL parameter, and then set it to be the circle of the newly created role. Easy enough.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># GET /circles/:circle_id/roles/new</span>
<span class="k">def</span> <span class="nf">new</span>
<span class="vi">@circle</span> <span class="o">=</span> <span class="no">Circle</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:circle_id</span><span class="p">])</span>
<span class="vi">@role</span> <span class="o">=</span> <span class="vi">@circle</span><span class="p">.</span><span class="nf">roles</span><span class="p">.</span><span class="nf">new</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Now letās look at the views. First, the <em>new</em> view still has a link back to the list of roles, and this will not work anymore because the list of roles is now always linked to a circle. So I will change that.</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><h1></span>New Role<span class="nt"></h1></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'form'</span><span class="p">,</span> <span class="ss">circle: </span><span class="vi">@circle</span><span class="p">,</span> <span class="ss">role: </span><span class="vi">@role</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Back'</span><span class="p">,</span> <span class="n">circle_roles_path</span><span class="p">(</span><span class="vi">@circle</span><span class="p">)</span> <span class="cp">%></span>
</code></pre></div></div>
<p>Can you spot the changes? In line 3, I have added another parameter to the form, the <code class="language-plaintext highlighter-rouge">@circle</code> variable, so that the form can use it. Also, I have changed the <em>back</em> link to use a different helper function that will return the right URL to the list of roles <em>for this circle</em>.</p>
<p>By the way, the way Rails creates these scaffolds, the same form is used for new entities and to edit existing entities. This is why the actual form is not implemented in the views themselves, like here, but included as what Rails calls a āpartialā. Essentially, this is a plain old include.</p>
<p>The form tag itself is created with a form helper method, that needs to know about the fact the resource is dependent on another resource. This is because the HTML <code class="language-plaintext highlighter-rouge">FORM</code> tag needs an URL which has to be in the correct format. Fortunately the form helper is smart, so the change is easy.</p>
<p>Generated code:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="n">role</span><span class="p">,</span> <span class="ss">local: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
...
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre></div></div>
<p>Adapted code:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="p">[</span><span class="n">circle</span><span class="p">,</span> <span class="n">role</span><span class="p">],</span> <span class="ss">local: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
...
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre></div></div>
<p>See how I just passed an list of entities instead of the single entity before? This is how Rails makes common tasks easy.</p>
<p>Finally, I will remove the edit field for the circle from the form completely because the user is not intended to change the circle a role belongs to.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># Delete these lines</span>
<span class="o"><</span><span class="n">div</span> <span class="k">class</span><span class="o">=</span><span class="s2">"field"</span><span class="o">></span>
<span class="o"><</span><span class="sx">%= form.label :circle_id %>
<%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">text_field</span> <span class="ss">:circle_id</span> <span class="o">%></span>
<span class="o"><</span><span class="sr">/div>
</span></code></pre></div></div>
<p>When the form is submitted, the <code class="language-plaintext highlighter-rouge">create</code> method in the <code class="language-plaintext highlighter-rouge">RolesController</code> is called. Here, I need to set the new roleās circle parameter correctly. The original, generated code looks like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># POST /roles</span>
<span class="c1"># POST /roles.json</span>
<span class="k">def</span> <span class="nf">create</span>
<span class="vi">@role</span> <span class="o">=</span> <span class="no">Role</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">role_params</span><span class="p">)</span>
<span class="n">respond_to</span> <span class="k">do</span> <span class="o">|</span><span class="nb">format</span><span class="o">|</span>
<span class="k">if</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">save</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">html</span> <span class="p">{</span> <span class="n">redirect_to</span> <span class="vi">@role</span><span class="p">,</span> <span class="ss">notice: </span><span class="s1">'Role was successfully created.'</span> <span class="p">}</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">json</span> <span class="p">{</span> <span class="n">render</span> <span class="ss">:show</span><span class="p">,</span> <span class="ss">status: :created</span><span class="p">,</span> <span class="ss">location: </span><span class="vi">@role</span> <span class="p">}</span>
<span class="k">else</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">html</span> <span class="p">{</span> <span class="n">render</span> <span class="ss">:new</span> <span class="p">}</span>
<span class="nb">format</span><span class="p">.</span><span class="nf">json</span> <span class="p">{</span> <span class="n">render</span> <span class="ss">json: </span><span class="vi">@role</span><span class="p">.</span><span class="nf">errors</span><span class="p">,</span> <span class="ss">status: :unprocessable_entity</span> <span class="p">}</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I will adjust the comments, extract the circle from the request parameters, and set the circle accordingly; just two more lines at the beginning.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># POST /circles/:circle_id/roles</span>
<span class="c1"># POST /circles/:circle_id/roles.json</span>
<span class="k">def</span> <span class="nf">create</span>
<span class="vi">@circle</span> <span class="o">=</span> <span class="no">Circle</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:circle_id</span><span class="p">])</span>
<span class="vi">@role</span> <span class="o">=</span> <span class="no">Role</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">role_params</span><span class="p">)</span>
<span class="vi">@role</span><span class="p">.</span><span class="nf">circle</span> <span class="o">=</span> <span class="vi">@circle</span>
<span class="o">...</span>
</code></pre></div></div>
<p>When the creation is successful, the browser is redirected to the <code class="language-plaintext highlighter-rouge">show</code> method of the controller. This is done with the <code class="language-plaintext highlighter-rouge">redirect_to</code> function that you can see in the generated code above. It creates a corresponding HTTP response code (302) with the appropriate URL. However, the generated <code class="language-plaintext highlighter-rouge">show</code> view still contains a link back to the list of roles, so we need to fix that the same way as before.</p>
<p>The generated code in <code class="language-plaintext highlighter-rouge">holo/app/views/role/show.html.erb</code>:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><p</span> <span class="na">id=</span><span class="s">"notice"</span><span class="nt">></span><span class="cp"><%=</span> <span class="n">notice</span> <span class="cp">%></span><span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Name:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Person:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">person_id</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Circle:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">circle_id</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Edit'</span><span class="p">,</span> <span class="n">edit_role_path</span><span class="p">(</span><span class="vi">@role</span><span class="p">)</span> <span class="cp">%></span> |
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Back'</span><span class="p">,</span> <span class="n">roles_path</span> <span class="cp">%></span>
</code></pre></div></div>
<p>I will also fix it so that instead of the circle and person IDs, their names are displayed.</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><p</span> <span class="na">id=</span><span class="s">"notice"</span><span class="nt">></span><span class="cp"><%=</span> <span class="n">notice</span> <span class="cp">%></span><span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Name:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Person:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">person</span><span class="o">&</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="nt"><p></span>
<span class="nt"><strong></span>Circle:<span class="nt"></strong></span>
<span class="cp"><%=</span> <span class="vi">@role</span><span class="p">.</span><span class="nf">circle</span><span class="p">.</span><span class="nf">name</span> <span class="cp">%></span>
<span class="nt"></p></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Edit'</span><span class="p">,</span> <span class="n">edit_role_path</span><span class="p">(</span><span class="vi">@role</span><span class="p">)</span> <span class="cp">%></span> |
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Back'</span><span class="p">,</span> <span class="n">circle_roles_path</span><span class="p">(</span><span class="vi">@role</span><span class="p">.</span><span class="nf">circle</span><span class="p">)</span> <span class="cp">%></span>
</code></pre></div></div>
<p>There is something that is easy to overlook. Remember that I changed roles so that they can be assigned to no one? If you check the line where I print the personās name, I am using the <code class="language-plaintext highlighter-rouge">&.</code> operator. This is much like the <code class="language-plaintext highlighter-rouge">.</code> that is used to access a data structure in languages as early as C, but with the additional quirk that <em>if the parent element is null (or nil in Ruby), it returns immediately</em>. This is to avoid to have to write out <code class="language-plaintext highlighter-rouge">if role.person.nil? role.person.name else "nobody" end</code> every time. Of course, I can still do that if I want to do something specific like actually printing ānobodyā. But it is a handy shortcut, a bit like Elmās <code class="language-plaintext highlighter-rouge">Maybe.withDefault</code>, except that is not really much of a shortcut.</p>
<p>To finish this exercise on dependent resources, I will change the edit view for roles. The generated code looks like this:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><h1></span>Editing Role<span class="nt"></h1></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'form'</span><span class="p">,</span> <span class="ss">role: </span><span class="vi">@role</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Show'</span><span class="p">,</span> <span class="vi">@role</span> <span class="cp">%></span> |
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Back'</span><span class="p">,</span> <span class="n">roles_path</span> <span class="cp">%></span>
</code></pre></div></div>
<p>Remember I now need to pass a reference to the circle to the form. However, do you also remember the <code class="language-plaintext highlighter-rouge">shallow: true</code> option I used. This means, that for editing, I donāt need the full URL but I can just use <code class="language-plaintext highlighter-rouge">GET /roles/1/edit</code> instead. Nevertheless, I need to pass in something. This is a common situation, so Rails handles is simply and gracefully. I will simply pass in <code class="language-plaintext highlighter-rouge">nil</code> (Robyās equivalent of a null reference) and it will silently ignore the nesting.</p>
<p>Also, I need to change the <code class="language-plaintext highlighter-rouge">roles_path</code> once more, just as above.</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><h1></span>Editing Role<span class="nt"></h1></span>
<span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'form'</span><span class="p">,</span> <span class="ss">circle: </span><span class="kp">nil</span><span class="p">,</span> <span class="ss">role: </span><span class="vi">@role</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Show'</span><span class="p">,</span> <span class="vi">@role</span> <span class="cp">%></span> |
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Back'</span><span class="p">,</span> <span class="n">circle_roles_path</span><span class="p">(</span><span class="vi">@role</span><span class="p">.</span><span class="nf">circle</span><span class="p">)</span> <span class="cp">%></span>
</code></pre></div></div>
<h2 id="finishing-off">Finishing off</h2>
<p>Now I am finally done with converting the Roles to a dependent resource. To finish off, I will add a little ābusiness logicā to the Circles, so that a set of standard roles is automatically created for each new circle, just like Holocracy demands it. I will add this to the <code class="language-plaintext highlighter-rouge">create</code> method of the <code class="language-plaintext highlighter-rouge">CircleController</code>.</p>
<p>As a last addition, I will ensure that roles are deleted when their circle is destroyed.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Circle</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">has_many</span> <span class="ss">:roles</span><span class="p">,</span> <span class="ss">dependent: :destroy</span>
<span class="n">has_many</span> <span class="ss">:people</span><span class="p">,</span> <span class="ss">through: :roles</span>
<span class="n">validates</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="n">before_create</span> <span class="k">do</span> <span class="o">|</span><span class="n">circle</span><span class="o">|</span>
<span class="n">fac</span> <span class="o">=</span> <span class="n">circle</span><span class="p">.</span><span class="nf">roles</span><span class="p">.</span><span class="nf">new</span>
<span class="n">fac</span><span class="p">.</span><span class="nf">name</span> <span class="o">=</span> <span class="s2">"Facilitator"</span>
<span class="n">sec</span> <span class="o">=</span> <span class="n">circle</span><span class="p">.</span><span class="nf">roles</span><span class="p">.</span><span class="nf">new</span>
<span class="n">sec</span><span class="p">.</span><span class="nf">name</span> <span class="o">=</span> <span class="s2">"Secretary"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The option <code class="language-plaintext highlighter-rouge">dependent: :destroy</code> ensures that roles are deleted together with the circle. Done. (I may implement some extra precautions later, such as not allowing to delete a circle with people in it.)</p>
<p>The <code class="language-plaintext highlighter-rouge">before_create</code> is a callback which is called, well, before the object is created. Here, I create two new roles for the new circle. They will get stored together with the circle. Simple and neat to initialize an object beyond just default values.</p>
<h2 id="summary">Summary</h2>
<p>It may seem as if this was a lot of technicalities. But the truth is that I just had to walk through the cycle of request routes and controller actions, including the corresponding views, to ensure everything is passed on correctly. But for a structural change in a full web application, this seems rather simple. I like Rails for things like this. It keeps easy changes easy while complex ones are still possible, unlike many ācodelessā tools that make simple things even easier, and complex ones near to impossible.</p>In the previous part of the series, I have shown how to quickly create a set of models, controllers, and views, plus some other useful stuff, to implement a tool to support the Holocracy method of running an organization. However, the tool was not much more than a database browser at this time, which is neat enough for ten minutes of work, but letās go a little further.Holocracy on Rails2021-01-10T00:00:00+00:002021-01-10T00:00:00+00:00https://heinecke.com/blog/2021/01/10/holocracy-on-rails<p>Recently, I have rediscovered <a href="https://rubyonrails.org/">Ruby on Rails</a>. In my opinion, it is still the best framework if you want to shell out a simple, CRUD based web application in a short time. Beyond that, is of course capable of much more but this is what it excels at. You donāt need to worry too much about basic security features, e.g. cross-site scripting, and you get fully functional web pages for your models out of the box.</p>
<p>On top, you get a REST API for free, which is handy when you want to replace the simple HTML front-end with some more sophisticated JavaScript-based, interactive UI. Or <a href="https://elm-lang.org/">Elm</a>-based, for that matter.</p>
<h2 id="witnessing-meetings">Witnessing meetings</h2>
<p>The whole train of thought came up because I am not really good at routine tasks. At the same time, meetings with people to work on certain topics are a large part of my work.</p>
<p>One of the problems with meetings is that, in the best case, everybody comes out of the meeting with a good feeling of understanding and a clear picture of what needs to be done. But then, thirty minutes later, if you ask two people independently what was decided, they will already tell you different stories. That is just how the human brain works. We build models in our brain and they are not the same for every person. When we test the models of two different people with questions, then they will result in different answers. This effect is well researched and every police officer interrogating witnesses will confirm it.</p>
<p>But meetings donāt always go that well. I have experienced meetings where not everybody was sure about the <em>purpose</em> of the meeting, the <em>authority</em> of the group meeting for the purpose, or the <em>roles</em> of the various participants. These meetings tend to feel a bit forced as the agenda (if there is an agenda) is worked through and there is a lot of silence in between, which is usually taken as agreement with whatever is being presented.</p>
<p>And then there is the worst scenario, where there are tensions of various kinds create conflict that is hard to resolve. Often, the actual tensions are not explored, the reasons not understood, and so it is difficult to address them. Iām not saying that understanding the reasons will make the tensions magically go awayābut <em>not</em> understanding them will certainly not help.</p>
<h2 id="holocracy">Holocracy</h2>
<p>There is a book out there (there is always a book), that gives a formal framework for structuring an organization into circles and providing guidance like templates and rule books. It is called āHolacracyā after the method the authors are proposing. I disagree with the name because there is no āaā in Greek į½ Ī»ĪæĻ, <em>hĆ³los</em> āwholeā. But that is a discussion for another day. Just note that I use a spelling I personally find more appropriate, but if you want to buy the book or visit the <a href="https://www.holacracy.org/">web site</a>, mind the different spelling.</p>
<p>Holocracy proposes to structure an organization into a hierarchical structure of ācirclesā, i.e. groups of people, and a āconstitutionā that they follow and that provides basic information like the purpose of the group, its authority, the roles in the group, and its inner workings and interaction with other groups. It specifically addresses the problems I have mentioned in the previous section: The need for creating agendas and keeping minutes, the need to define purpose, the need to address tensions. For me as a programmer, it is quite appealing because Holocracy lends itself well to implementation in a tool. It is almost like an algorithm for organizations. (And that may well be its greatest flaw, but that is another story that will be told another time.)</p>
<p>The Holocracy advocates claim of course that it is not the tool that makes the method successful but really it is a change of culture and a different mindset. And yes, that is most likely true. As the saying goes: A fool with a tool is still a fool, just a more dangerous one. But I am a programmer and I am bad at routine jobs.</p>
<p>There are already implementations of Holocracy tools out there but in the end, it is not that hard. A simple web application can capture the mechanical aspects and leave your head free to do the mind shift. And what programmer would I be if I did not write my own implementation of it?</p>
<h2 id="finally-rails">Finally, Rails</h2>
<p>And this is where Ruby on Rails enters the picture. Defining a relatively simple domain model (circles, people, agendas, decisions, etc.) with some simple algorithms operating on them, that is something that can very easily done with Rails. For now, I will not at all care about styling the web pages and focus on functionality. Chances are that the front-end will be replaced by some neat browser-side code anyway. It is more important to get the basic structure in place.</p>
<p>Implementing the tool will be too much for a single article, so this might turn into another series of Saturday projects. To give you a flavor though, letās start by creating an implementation for Circles, People, and the Roles. I am assuming that <a href="https://guides.rubyonrails.org/getting_started.html">Rails is already installed</a>, which I suggest you do in a *nix environment. If you are on Windows, the <a href="https://docs.microsoft.com/windows/wsl/about">Windows Subsystem for Linux</a> will do nicely, even though it can be a bit slow. I start, as in so many other frameworks, by creating a new Rails application in a convenient directory.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>rails new holo
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create Gemfile
run git init from <span class="s2">"."</span>
...
āā utils-merge@1.0.1
āā wbuf@1.7.3
āā webpack-dev-middleware@3.7.3
āā webpack-dev-server@3.11.1
āā websocket-driver@0.7.4
āā websocket-extensions@0.1.4
āā ws@6.2.1
Done <span class="k">in </span>73.22s.
Webpacker successfully installed š š°
<span class="nv">$ </span><span class="nb">cd </span>holo
</code></pre></div></div>
<h3 id="creating-the-scaffolds">Creating the scaffolds</h3>
<p>After grinding away for some time, a subdirectory for the app is created and populated with quite a massive amount of stuff. (These are technical terms.) I change into the new subdirectory and create scaffolds for my three entities:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails generate scaffold Person name:string email:string
Running via Spring preloader <span class="k">in </span>process 357
invoke active_record
create db/migrate/20210108141507_create_people.rb
create app/models/person.rb
invoke test_unit
...
create app/assets/stylesheets/people.scss
invoke scss
create app/assets/stylesheets/scaffolds.scss
</code></pre></div></div>
<p>A <em>scaffold</em> is a database table, a model class in rails, a controller class, a set of views for the model, and a set of test classes for all of those things. Also, the routes (or URLs) through which these things can be accessed are automatically created, as well as a full REST API for the common operations. Neat? Let me do the other two.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails generate scaffold Circle name:string purpose:text
Running via Spring preloader <span class="k">in </span>process 391
invoke active_record
create db/migrate/20210108141830_create_circles.rb
create app/models/circle.rb
...
</code></pre></div></div>
<p>And finally:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails generate scaffold Role name:string person:references circle:references
Running via Spring preloader <span class="k">in </span>process 426
invoke active_record
create db/migrate/20210108141933_create_roles.rb
...
</code></pre></div></div>
<p>Note how I simply specified that a role will <em>reference</em> a person and a circle. Rails will pick that up and do the right thing based on matching the names of things.</p>
<h3 id="creating-the-database-schema">Creating the database schema</h3>
<p>Now the code is in place. Next, I will look at the database schema creation, which is done in code, as it should be. For this, Rails creates <em>migration</em> classes. These can be adjusted as necessary and then run against a development database, which is of course already set up by the framework. Why would I need to do that by hand, after all?</p>
<p>This is the automatically created Person schema migration:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CreatePeople</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">6.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:people</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>It creates a table with two string columns. Ignore the <code class="language-plaintext highlighter-rouge">timestamps</code> for now; this is part of the optimistic transaction strategy that Rails employs. But we might want to ensure that both name and email are given for every person, and that the email is unique as it identifies the user. I will add this to the migration before I execute it.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CreatePeople</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">6.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:people</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span>
<span class="n">t</span><span class="p">.</span><span class="nf">index</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">unique: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Pretty self-explanatory. I will also have a look at the Role schema migration. Here is the generated code:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CreateRoles</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">6.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:roles</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:person</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:circle</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>This looks pretty much perfect already. I will just add another non-null constraint and a default value for the name.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">CreateRoles</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Migration</span><span class="p">[</span><span class="mf">6.0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">change</span>
<span class="n">create_table</span> <span class="ss">:roles</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
<span class="n">t</span><span class="p">.</span><span class="nf">string</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">default: </span><span class="s2">"Unnamed Circle"</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:person</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">references</span> <span class="ss">:circle</span><span class="p">,</span> <span class="ss">null: </span><span class="kp">false</span><span class="p">,</span> <span class="ss">foreign_key: </span><span class="kp">true</span>
<span class="n">t</span><span class="p">.</span><span class="nf">timestamps</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Now, I am all set to run the migrations:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails db:migrate
<span class="o">==</span> 20210108141507 CreatePeople: migrating <span class="o">=====================================</span>
<span class="nt">--</span> create_table<span class="o">(</span>:people<span class="o">)</span>
-> 0.0158s
<span class="o">==</span> 20210108141507 CreatePeople: migrated <span class="o">(</span>0.0159s<span class="o">)</span> <span class="o">============================</span>
<span class="o">==</span> 20210108141830 CreateCircles: migrating <span class="o">====================================</span>
<span class="nt">--</span> create_table<span class="o">(</span>:circles<span class="o">)</span>
-> 0.0115s
<span class="o">==</span> 20210108141830 CreateCircles: migrated <span class="o">(</span>0.0117s<span class="o">)</span> <span class="o">===========================</span>
<span class="o">==</span> 20210108141933 CreateRoles: migrating <span class="o">======================================</span>
<span class="nt">--</span> create_table<span class="o">(</span>:roles<span class="o">)</span>
-> 0.0239s
<span class="o">==</span> 20210108141933 CreateRoles: migrated <span class="o">(</span>0.0241s<span class="o">)</span> <span class="o">=============================</span>
</code></pre></div></div>
<p>All set. For fun, letās have a look at the actual database. For development, I am using <a href="https://www.sqlite.org/index.html">SQLite3</a>, which of course will be replaced by something more robust like PostgreSQL or MariaDB for production. Fortunately, Rails abstracts away all the idiosyncrasies of the underlying databases unless I specifically want to use them.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails dbconsole
SQLite version 3.31.1 2020-01-27 19:55:54
Enter <span class="s2">".help"</span> <span class="k">for </span>usage hints.
sqlite> .tables
ar_internal_metadata people schema_migrations
circles roles
sqlite> .schema people
CREATE TABLE IF NOT EXISTS <span class="s2">"people"</span> <span class="o">(</span><span class="s2">"id"</span> integer PRIMARY KEY AUTOINCREMENT NOT NULL, <span class="s2">"name"</span> varchar NOT NULL, <span class="s2">"email"</span> varchar NOT NULL, <span class="s2">"created_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL, <span class="s2">"updated_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL<span class="o">)</span><span class="p">;</span>
CREATE UNIQUE INDEX <span class="s2">"index_people_on_email"</span> ON <span class="s2">"people"</span> <span class="o">(</span><span class="s2">"email"</span><span class="o">)</span><span class="p">;</span>
sqlite> .schema roles
CREATE TABLE IF NOT EXISTS <span class="s2">"roles"</span> <span class="o">(</span><span class="s2">"id"</span> integer PRIMARY KEY AUTOINCREMENT NOT NULL, <span class="s2">"name"</span> varchar DEFAULT <span class="s1">'Unnamed Circle'</span> NOT NULL, <span class="s2">"person_id"</span> integer NOT NULL, <span class="s2">"circle_id"</span> integer NOT NULL, <span class="s2">"created_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL, <span class="s2">"updated_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL, CONSTRAINT <span class="s2">"fk_rails_7a19f4fbb4"</span>
FOREIGN KEY <span class="o">(</span><span class="s2">"person_id"</span><span class="o">)</span>
REFERENCES <span class="s2">"people"</span> <span class="o">(</span><span class="s2">"id"</span><span class="o">)</span>
, CONSTRAINT <span class="s2">"fk_rails_3cae5e4d90"</span>
FOREIGN KEY <span class="o">(</span><span class="s2">"circle_id"</span><span class="o">)</span>
REFERENCES <span class="s2">"circles"</span> <span class="o">(</span><span class="s2">"id"</span><span class="o">)</span>
<span class="o">)</span><span class="p">;</span>
CREATE INDEX <span class="s2">"index_roles_on_person_id"</span> ON <span class="s2">"roles"</span> <span class="o">(</span><span class="s2">"person_id"</span><span class="o">)</span><span class="p">;</span>
CREATE INDEX <span class="s2">"index_roles_on_circle_id"</span> ON <span class="s2">"roles"</span> <span class="o">(</span><span class="s2">"circle_id"</span><span class="o">)</span><span class="p">;</span>
sqlite> .schema circles
CREATE TABLE IF NOT EXISTS <span class="s2">"circles"</span> <span class="o">(</span><span class="s2">"id"</span> integer PRIMARY KEY AUTOINCREMENT NOT NULL, <span class="s2">"name"</span> varchar, <span class="s2">"purpose"</span> text, <span class="s2">"created_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL, <span class="s2">"updated_at"</span> datetime<span class="o">(</span>6<span class="o">)</span> NOT NULL<span class="o">)</span><span class="p">;</span>
</code></pre></div></div>
<p>If you are SQL inclined, you can wade through this and confirm that Rails actually did the right thing. Obviously, I have left away quite a lot of things, most notably user authentication. I can add this later as there are ready-made solutions, <em>gems</em> in Ruby lingo, for it. Next, I will have a look at models.</p>
<h3 id="looking-at-models">Looking at models</h3>
<p>A model is a Ruby representation of a domain concept. Rails has automatically create three of them, as instructed, and it will be able to store them in and retrieve them from the database. However, I want to do a little more. Instead of working with IDs and foreign keys, I want Rails to populate collections automatically and efficiently where entites refer to each other. To do that, I will amend the models.</p>
<p>The basic model is empty because it inherits all of its behavior from a framework superclass:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Person</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="k">end</span>
</code></pre></div></div>
<p>So I will help Rails by adding some information about its place in the world:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Person</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">has_many</span> <span class="ss">:roles</span>
<span class="n">has_many</span> <span class="ss">:circles</span><span class="p">,</span> <span class="ss">through: :roles</span>
<span class="n">validates</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="n">validates</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">uniqueness: </span><span class="kp">true</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Again, I find this pretty self-explanatory. The <code class="language-plaintext highlighter-rouge">through</code> phrase tells the Person model that its relationship to Circles is many-to-many and Roles are actually used as the intermediary, the join table in SQL lingo. The <code class="language-plaintext highlighter-rouge">presence</code> phrase checks that the name or email are neither null nor a zero length string. Convenient.</p>
<p>Letās have a look at the other two model classes:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Circle</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">has_many</span> <span class="ss">:roles</span>
<span class="n">has_many</span> <span class="ss">:people</span><span class="p">,</span> <span class="ss">through: :roles</span>
<span class="n">validates</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="k">end</span>
</code></pre></div></div>
<p>The Role class is already prepopulated a little more, because when we created the scaffold, we told it already to <code class="language-plaintext highlighter-rouge">reference</code> the Circles and People. This is the generated code:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Role</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">belongs_to</span> <span class="ss">:person</span>
<span class="n">belongs_to</span> <span class="ss">:circle</span>
<span class="k">end</span>
</code></pre></div></div>
<p>I only need to add some validation to make the user interface aware.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Role</span> <span class="o"><</span> <span class="no">ApplicationRecord</span>
<span class="n">belongs_to</span> <span class="ss">:person</span>
<span class="n">belongs_to</span> <span class="ss">:circle</span>
<span class="n">validates</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="n">validates</span> <span class="ss">:person</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="n">validates</span> <span class="ss">:circle</span><span class="p">,</span> <span class="ss">presence: </span><span class="kp">true</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Done.</p>
<h3 id="trying-it-out">Trying it out</h3>
<p>Now letās see what we have done. Rails comes with a simple server for development purposes.</p>
<p>Before we try it out, let me save you a little googling. If you are on a proper *nix machine, skip to the next paragraph. But if you are in Windows and using the Windows Subsystem for Linux to follow along, please change the file <code class="language-plaintext highlighter-rouge">holo/config/environments/development.rb</code> as follows to circumvent some quirks of this platform:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">configure</span> <span class="k">do</span>
<span class="o">...</span>
<span class="c1"># Add this line anywhere:</span>
<span class="n">config</span><span class="p">.</span><span class="nf">web_console</span><span class="p">.</span><span class="nf">permissions</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'192.168.0.0/16'</span><span class="p">,</span> <span class="s1">'172.16.0.0/12'</span><span class="p">,</span> <span class="s1">'10.0.0.0/8'</span><span class="p">]</span>
<span class="o">...</span>
<span class="c1"># Find this line and change it as follows:</span>
<span class="c1"># config.file_watcher = ActiveSupport::EventedFileUpdateChecker</span>
<span class="n">config</span><span class="p">.</span><span class="nf">file_watcher</span> <span class="o">=</span> <span class="no">ActiveSupport</span><span class="o">::</span><span class="no">FileUpdateChecker</span>
<span class="o">...</span>
</code></pre></div></div>
<p>This will allow you to use the web console, a useful debugging tool, in your browser, and it will ensure that the Rails development server can pick up changes in your source code and immediately serve them to you despite the ~broken~ special Windows file system.</p>
<p>Now is the big time. I start the development server like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bin/rails s <span class="nt">-b</span> 0.0.0.0
<span class="o">=></span> Booting Puma
<span class="o">=></span> Rails 6.0.3.4 application starting <span class="k">in </span>development
<span class="o">=></span> Run <span class="sb">`</span>rails server <span class="nt">--help</span><span class="sb">`</span> <span class="k">for </span>more startup options
Puma starting <span class="k">in </span>single mode...
<span class="k">*</span> Version 4.3.7 <span class="o">(</span>ruby 2.7.2-p137<span class="o">)</span>, codename: Mysterious Traveller
<span class="k">*</span> Min threads: 5, max threads: 5
<span class="k">*</span> Environment: development
<span class="k">*</span> Listening on tcp://0.0.0.0:3000
</code></pre></div></div>
<p>And there we go. I donāt want to see the Hello World page Rails automatically created so I point my browser to the appropriate IP address and request the <code class="language-plaintext highlighter-rouge">/people</code> page.</p>
<p><img src="/j/assets/series/holo-rails/people-01.png" alt="The initial people page" class="centered" /></p>
<p>Awesome. I like the no nonsense style. More seriously, of course I can use all kinds of CSS and whatnot to make it suit my taste but this is about function and not style. To prove it, letās use the REST API instead.</p>
<p><img src="/j/assets/series/holo-rails/people-json-02.png" alt="No people in JSON" class="centered" /></p>
<p>This is what no people look like in JSON. And we had to do nothing additional to get this API. Now go build your fancy Angular front-end on top of that. But fist, letās add some people. Iāll go back to the web page and click āAdd Personā. Letās look at the web page.</p>
<p><img src="/j/assets/series/holo-rails/people-new-01.png" alt="New person" class="centered" /></p>
<p>This is not ideal. The web page uses a standard text field for the email field. I want to harness the power of HTML5 and tell the browser that this is a text field. I will edit the form source code for this. Here is the generated code:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="n">person</span><span class="p">,</span> <span class="ss">local: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
<span class="cp"><%</span> <span class="k">if</span> <span class="n">person</span><span class="p">.</span><span class="nf">errors</span><span class="p">.</span><span class="nf">any?</span> <span class="cp">%></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"error_explanation"</span><span class="nt">></span>
<span class="nt"><h2></span><span class="cp"><%=</span> <span class="n">pluralize</span><span class="p">(</span><span class="n">person</span><span class="p">.</span><span class="nf">errors</span><span class="p">.</span><span class="nf">count</span><span class="p">,</span> <span class="s2">"error"</span><span class="p">)</span> <span class="cp">%></span> prohibited this person from being saved:<span class="nt"></h2></span>
<span class="nt"><ul></span>
<span class="cp"><%</span> <span class="n">person</span><span class="p">.</span><span class="nf">errors</span><span class="p">.</span><span class="nf">full_messages</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">message</span><span class="o">|</span> <span class="cp">%></span>
<span class="nt"><li></span><span class="cp"><%=</span> <span class="n">message</span> <span class="cp">%></span><span class="nt"></li></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"></ul></span>
<span class="nt"></div></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:name</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">text_field</span> <span class="ss">:name</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:email</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">text_field</span> <span class="ss">:email</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"actions"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">submit</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre></div></div>
<p>It is the weird mix of HTML and Ruby that you will have seen in other templating engines before. Rails provided s lot of helpers to do the usual things. So indeed, I will use an <code class="language-plaintext highlighter-rouge">email_field</code> instead of the <code class="language-plaintext highlighter-rouge">text_field</code>:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="n">person</span><span class="p">,</span> <span class="ss">local: </span><span class="kp">true</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span>
...
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">label</span> <span class="ss">:email</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">form</span><span class="p">.</span><span class="nf">email_field</span> <span class="ss">:email</span> <span class="cp">%></span>
<span class="nt"></div></span>
...
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
</code></pre></div></div>
<p>And indeed, now the browser shows this:</p>
<p><img src="/j/assets/series/holo-rails/people-new-02.png" alt="New person with email field" class="centered" /></p>
<p>Letās add someone nameless.</p>
<p><img src="/j/assets/series/holo-rails/people-new-03.png" alt="They are nobody" class="centered" /></p>
<p>We are not happy. I will add a proper name.</p>
<p><img src="/j/assets/series/holo-rails/people-new-04.png" alt="They are nobody" class="centered" /></p>
<p>And letās go back to the people overview.</p>
<p><img src="/j/assets/series/holo-rails/people-05.png" alt="They are nobody" class="centered" /></p>
<p>Ha! I have added you as well. Sneaky, huh?</p>
<h3 id="summary">Summary</h3>
<p>Now this may not seem like much but really it is. Keep in mind that all of this happened in only a few minutes, and I have already create the same functionality for circles and roles.</p>
<p>For now, the article is already quite long, so I will continue another day.</p>Recently, I have rediscovered Ruby on Rails. In my opinion, it is still the best framework if you want to shell out a simple, CRUD based web application in a short time. Beyond that, is of course capable of much more but this is what it excels at. You donāt need to worry too much about basic security features, e.g. cross-site scripting, and you get fully functional web pages for your models out of the box.Functional programming with Elm, part 42020-12-27T00:00:00+00:002020-12-27T00:00:00+00:00https://heinecke.com/blog/2020/12/27/fp-with-elm-04<p>In the <a href="/blog/2020/12/23/fp-with-elm-03.html">previous part of the series</a>, we implemented curved tracks and movement along them. This time, we will finally look at branching train lines.</p>
<p>We have already used a graph to store our layout, so we <em>can</em> have multiple connected track. We just have not used it so far. Let me show you the function that initializes the layout I have been using in the samples.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">initialLayout</span> <span class="p">:</span> <span class="kt">Layout</span>
<span class="n">initialLayout</span> <span class="o">=</span>
<span class="kt">Graph</span><span class="o">.</span><span class="n">empty</span>
<span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">0</span> <span class="mi">1</span> <span class="p">(</span><span class="kt">StraightTrack</span> <span class="p">{</span> <span class="n">length</span> <span class="o">=</span> <span class="mf">75.0</span> <span class="p">})</span>
<span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">1</span> <span class="mi">2</span> <span class="p">(</span><span class="kt">CurvedTrack</span> <span class="p">{</span> <span class="n">radius</span> <span class="o">=</span> <span class="mf">300.0</span><span class="o">,</span> <span class="n">angle</span> <span class="o">=</span> <span class="mf">15.0</span> <span class="p">})</span>
</code></pre></div></div>
<p>We are inserting edges so that track 0 connects to track 1, which then connectors to track 2. But now letās add a branching track.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">1</span> <span class="mi">3</span> <span class="p">(</span><span class="kt">StraightTrack</span> <span class="p">{</span> <span class="n">length</span> <span class="o">=</span> <span class="mf">75.0</span> <span class="p">})</span>
</code></pre></div></div>
<p>That was easy.</p>
<p>If we want to switch the track the train is using, we have to keep track which of the possible connections is active. Remember how we defined the layout graph?</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="k">alias</span> <span class="kt">Layout</span> <span class="o">=</span>
<span class="kt">Graph</span> <span class="kt">Int</span> <span class="p">()</span> <span class="kt">Track</span>
</code></pre></div></div>
<p>We specified that we donāt want to store any particular data for vertices. Now is the time to change that: There are different switch types, simple ones but also crossings for example. Letās define a type for switches and store it with the vertices in the layout graph. A switch is a list of <em>configurations of routes</em> that can be active, and āswitchingā means to change from one of the configurations to another one. A <em>route</em> is a pair of vertices that determines from where to where the route leads.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="k">alias</span> <span class="kt">Layout</span> <span class="o">=</span>
<span class="kt">Graph</span> <span class="kt">Int</span> <span class="kt">Switch</span> <span class="kt">Track</span>
<span class="k">type</span> <span class="k">alias</span> <span class="kt">Switch</span> <span class="o">=</span>
<span class="p">{</span> <span class="n">configs</span> <span class="p">:</span> <span class="kt">List</span> <span class="p">(</span><span class="kt">List</span> <span class="p">(</span> <span class="kt">Int</span><span class="o">,</span> <span class="kt">Int</span> <span class="p">))</span> <span class="p">}</span>
</code></pre></div></div>
<p>Letās write a function that returns all the switches in the layout. We want all the vertices in the layout graph that have switch data.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">switches</span> <span class="p">:</span> <span class="kt">Layout</span> <span class="o">-></span> <span class="kt">List</span> <span class="p">(</span> <span class="kt">Int</span><span class="o">,</span> <span class="kt">Switch</span> <span class="p">)</span>
<span class="n">switches</span> <span class="n">layout</span> <span class="o">=</span>
<span class="kt">Graph</span><span class="o">.</span><span class="n">nodes</span> <span class="n">layout</span>
<span class="c1">-- Convert from a list of pairs with a Maybe inside to a list of Maybes.</span>
<span class="o">|></span> <span class="kt">List</span><span class="o">.</span><span class="n">map</span> <span class="p">(</span><span class="o">\</span><span class="p">(</span> <span class="n">vertex</span><span class="o">,</span> <span class="n">data</span> <span class="p">)</span> <span class="o">-></span> <span class="kt">Maybe</span><span class="o">.</span><span class="n">map</span> <span class="p">(</span><span class="o">\</span><span class="n">switch</span> <span class="o">-></span> <span class="p">(</span> <span class="n">vertex</span><span class="o">,</span> <span class="n">switch</span> <span class="p">))</span> <span class="n">data</span><span class="p">)</span>
<span class="c1">-- Filter out the Nothings, the vertices that are not switches.</span>
<span class="o">|></span> <span class="kt">Maybe</span><span class="o">.</span><span class="kt">Extra</span><span class="o">.</span><span class="n">values</span>
</code></pre></div></div>
<p>Finally, we need to add the switch information to the initial layout.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">initialLayout</span> <span class="p">:</span> <span class="kt">Layout</span>
<span class="n">initialLayout</span> <span class="o">=</span>
<span class="kt">Graph</span><span class="o">.</span><span class="n">empty</span>
<span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">0</span> <span class="mi">1</span> <span class="p">(</span><span class="kt">StraightTrack</span> <span class="p">{</span> <span class="n">length</span> <span class="o">=</span> <span class="mf">75.0</span> <span class="p">})</span>
<span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">1</span> <span class="mi">2</span> <span class="p">(</span><span class="kt">CurvedTrack</span> <span class="p">{</span> <span class="n">radius</span> <span class="o">=</span> <span class="mf">300.0</span><span class="o">,</span> <span class="n">angle</span> <span class="o">=</span> <span class="mf">15.0</span> <span class="p">})</span>
<span class="o">|></span> <span class="n">insertEdgeData</span> <span class="mi">1</span> <span class="mi">3</span> <span class="p">(</span><span class="kt">StraightTrack</span> <span class="p">{</span> <span class="n">length</span> <span class="o">=</span> <span class="mf">75.0</span> <span class="p">})</span>
<span class="o">|></span> <span class="n">insertData</span> <span class="mi">1</span> <span class="p">(</span><span class="kt">Switch</span> <span class="p">[</span> <span class="p">[</span> <span class="p">(</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">2</span> <span class="p">)</span> <span class="p">]</span><span class="o">,</span> <span class="p">[</span> <span class="p">(</span> <span class="mi">0</span><span class="o">,</span> <span class="mi">3</span> <span class="p">)</span> <span class="p">]</span> <span class="p">])</span>
</code></pre></div></div>
<h2 id="next">Next</h2>
<p>This was a bit hard. We are beginning to utilize the mechanisms of functional programming to make our program more concise. If you think that the switches function takes a lot of computation, keep in mind that it only needs to be evaluated once for a given layout. Elm knows that its result will never change unless the layout is replaced with another one. So it can optimize away repeated calls to the function wherever we need them.</p>
<p>In the next part, we will make the switches actually switchable.</p>
<div id="train-4"></div>
<script src="/j/assets/series/fp-elm/main-4.js"></script>
<script>var app = Elm.Main.init({ node: document.getElementById("train-4") })</script>In the previous part of the series, we implemented curved tracks and movement along them. This time, we will finally look at branching train lines.Functional programming with Elm, part 32020-12-23T00:00:00+00:002020-12-23T00:00:00+00:00https://heinecke.com/blog/2020/12/23/fp-with-elm-03<p>In the <a href="/blog/2020/12/20/fp-with-elm-02.html">previous part of the series</a>, we implemented trains moving from one piece of track to the next. Our layout was still very constrained in that it only consisted of a series of straight tracks, and even though we used a graph to represent the layout internally, we did not yet utilize that power to implement branch lines. We will start with curves.</p>
<p>First, we need to put on our mathematicianās hat again. What does it mean to have a straight track or a curved track? For a straight track we already know part of the answer: Essentially, it has a length and nothing else. A curved track will have different specifications: The radius of the curve and the angle it covers. Its actual length can then be calculated using a function.</p>
<div class="sidenote">
<p>Side note: Real railway curves are much more complicated than circle segments. Among other things, they ease into their final radius gradually so the passengers heads donāt jerk due to the sudden centrifugal force when the train enters the curve. We will ignore this for now as it only makes the involved functions more complex without adding many additional points from as a programmer.</p>
</div>
<p>Elm provides <em>union types</em> to accommodate different variants of a data structures. They look like this:</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="kt">Track</span>
<span class="o">=</span> <span class="kt">StraightTrack</span>
<span class="p">{</span> <span class="n">length</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- in m</span>
<span class="p">}</span>
<span class="o">|</span> <span class="kt">CurvedTrack</span>
<span class="p">{</span> <span class="n">radius</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- in m</span>
<span class="o">,</span> <span class="n">angle</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- in degrees, why not</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Note that this time, <code class="language-plaintext highlighter-rouge">Track</code> is not a type <em>alias</em> anymore but a proper type. Type aliases work just like find and replace in your favorite text editor: We could have written the whole data structure in the curly braces everytime instead of the alias. A <em>type</em> is however its own thing, and here we tell Elm that it can have two wholly different shapes. The names <code class="language-plaintext highlighter-rouge">StraightTrack</code> and <code class="language-plaintext highlighter-rouge">CurvedTrack</code> serve as tags to identify which kind of data structure to expect.</p>
<p>To see how this works, have a look at the brand new <code class="language-plaintext highlighter-rouge">trackLength</code> function that calculates the value differently based on the type of track.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">trackLength</span> <span class="p">:</span> <span class="kt">Track</span> <span class="o">-></span> <span class="kt">Float</span>
<span class="n">trackLength</span> <span class="n">track</span> <span class="o">=</span>
<span class="k">case</span> <span class="n">track</span> <span class="k">of</span>
<span class="kt">StraightTrack</span> <span class="n">s</span> <span class="o">-></span>
<span class="n">s</span><span class="o">.</span><span class="n">length</span>
<span class="kt">CurvedTrack</span> <span class="n">c</span> <span class="o">-></span>
<span class="n">pi</span> <span class="o">*</span> <span class="n">c</span><span class="o">.</span><span class="n">radius</span> <span class="o">*</span> <span class="n">c</span><span class="o">.</span><span class="n">angle</span> <span class="o">/</span> <span class="mf">180.0</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">case ... of</code> syntax catches different variants of the Track type and the variable <code class="language-plaintext highlighter-rouge">s</code> or <code class="language-plaintext highlighter-rouge">c</code> is assigned the data structure within the specific type. From there, it is easy to handle the two cases and return the correct number. We have seen the <code class="language-plaintext highlighter-rouge">case ... of</code> syntax already when we use <code class="language-plaintext highlighter-rouge">Maybe</code>. Indeed, <code class="language-plaintext highlighter-rouge">Maybe</code> is defined as follows: <code class="language-plaintext highlighter-rouge">type Maybe a = Nothing | Just a</code>, where <code class="language-plaintext highlighter-rouge">a</code> is a <em>type variable</em> that can be replaced with any type of our choosing.</p>
<h2 id="next">Next</h2>
<p>In the next part we will finally implement branches in train tracks.</p>
<div id="train"></div>
<script src="/j/assets/series/fp-elm/main-3.js"></script>
<script>var app = Elm.Main.init({ node: document.getElementById("train") })</script>In the previous part of the series, we implemented trains moving from one piece of track to the next. Our layout was still very constrained in that it only consisted of a series of straight tracks, and even though we used a graph to represent the layout internally, we did not yet utilize that power to implement branch lines. We will start with curves.Functional programming with Elm, part 22020-12-20T00:00:00+00:002020-12-20T00:00:00+00:00https://heinecke.com/blog/2020/12/20/fp-with-elm-02<p>In the <a href="/blog/2020-12-19-functional-programming-with-elm">first part of this series</a>, I have talked a little about the functional programming paradigm, and I have shown what a simple simulation of a train moving on an infinite straight track looks like in Elm. But in reality, tracks are not infinite. The branch off each other and merge, and they end somewhere. In this part, I will explore a functional implementation of a train moving from one track to the next.</p>
<p>First, we need to look at the problem like a mathematician would. The concept in mathematics to describe connections is called a <em>graph</em>. The edges of the graph represent the individual pieces of railroad track, and the vertices represent the points where the tracks meet.</p>
<p><img src="/j/assets/series/fp-elm/figure-1.svg" alt="Figure 1: Representing a layout as a graph" /></p>
<p>First, we need to add a graph library to the project. This simply tells the package manager that we are going to use this particular add-on library.</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span>elm <span class="nb">install </span>drathier/elm-graph
<span class="go">Here is my plan:
Add:
drathier/elm-graph 4.0.0
elm/random 1.0.0
elm-community/list-extra 8.2.4
elm-community/maybe-extra 5.2.0
elm-community/random-extra 3.1.0
elm-explorations/test 1.2.2
owanturist/elm-union-find 1.0.0
Would you like me to update your elm.json accordingly? [Y/n]:
Success!
</span></code></pre></div></div>
<p>We need to define what we actually mean by a track. We will ignore curves, inclines, and other complications for now and stick to straight tracks, but with a certain, finite length.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="k">alias</span> <span class="kt">Track</span> <span class="o">=</span> <span class="p">{</span> <span class="n">length</span> <span class="p">:</span> <span class="kt">Float</span> <span class="p">}</span> <span class="c1">-- in m</span>
</code></pre></div></div>
<p>We can now use a graph to represent the connections between the tracks. I will call this data structure <code class="language-plaintext highlighter-rouge">Layout</code>.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="kt">Graph</span> <span class="k">exposing</span> <span class="p">(</span><span class="kt">Graph</span><span class="p">)</span>
<span class="k">type</span> <span class="k">alias</span> <span class="kt">Layout</span> <span class="o">=</span>
<span class="kt">Graph</span> <span class="kt">Int</span> <span class="p">()</span> <span class="kt">Track</span>
</code></pre></div></div>
<p>The import statement will not look too strange if you know your various script languages. The type alias means that we can use <code class="language-plaintext highlighter-rouge">Layout</code> as a shorthand for the specific type of graph we need.</p>
<p>Graph is actually a generic type that could hold all sorts of data. For our purpose, we want a graph that uses <code class="language-plaintext highlighter-rouge">Int</code> as keys for its vertices, that carries no extra data on the vertices, hence the <code class="language-plaintext highlighter-rouge">()</code>, and that uses <code class="language-plaintext highlighter-rouge">Track</code> to hold additional data about the edges. The <code class="language-plaintext highlighter-rouge">()</code> syntax is a tuple with zero elements, or Elmās idea of ānothing particular.ā As the connections in our layout do not have any additional information associated with them apart from just being there, we donāt need an additional type hereābut we will need that later when we get to switching between different branch lines.</p>
<div class="sidenote">
<p>As an aside, if you wonder about what is going on in the ādeclarationā of the Graph above: <code class="language-plaintext highlighter-rouge">Graph</code> refers to a <em>function</em> that returns a type, which is then assigned to the name <code class="language-plaintext highlighter-rouge">Layout</code>. That function takes three parameters, which are themselves types; in our case <code class="language-plaintext highlighter-rouge">Int</code>, <code class="language-plaintext highlighter-rouge">Track</code>, and <code class="language-plaintext highlighter-rouge">()</code>. A function like that is called a <a href="https://en.wikipedia.org/wiki/Type_constructor">type constructor</a>. Elm is somewhat limited in how you can work with types this way, e.g. I think you cannot have a list of type constructors <code class="language-plaintext highlighter-rouge">[Graph a b c, Tree a, Weird a]</code> and apply a certain type to them all at once. But thatās okay. In full-blown functional programming languages like <a href="https://www.haskell.org/">Haskell</a>, this is a major source of Power.</p>
<p>You may have heard that functional programming uses Ī» (lambda) calculus. A system that can construct types this way through functions is called <a href="https://en.wikipedia.org/wiki/Lambda_cube#(F%CF%89)_System_F%CF%89">FĻ (F-omega) calculus</a>. If you are curious, there is even one more level to achieve beyond that, the Calculus of Constructions, Ī»C. But then, in mathematics there is always another level.</p>
</div>
<h2 id="moving-on">Moving on</h2>
<p>We need to amend the train state with the track the train is currently on. Each track is identified by the two vertices it connects. I will define a new record type for the train location that contains the position of the train on the current track, the two vertex numbers for the current track, and, for convenience, the track information itself.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="k">alias</span> <span class="kt">TrainState</span> <span class="o">=</span>
<span class="p">{</span> <span class="n">name</span> <span class="p">:</span> <span class="kt">String</span>
<span class="o">,</span> <span class="n">length</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- in m</span>
<span class="o">,</span> <span class="n">speed</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- in m/s</span>
<span class="o">,</span> <span class="n">location</span> <span class="p">:</span> <span class="kt">Maybe</span> <span class="kt">TrainLocation</span>
<span class="p">}</span>
<span class="k">type</span> <span class="k">alias</span> <span class="kt">TrainLocation</span> <span class="o">=</span>
<span class="p">{</span> <span class="n">edge</span> <span class="p">:</span> <span class="p">(</span> <span class="kt">Int</span><span class="o">,</span> <span class="kt">Int</span> <span class="p">)</span> <span class="c1">-- The vertices</span>
<span class="o">,</span> <span class="n">pos</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- The position on the track in m from the first vertex</span>
<span class="o">,</span> <span class="n">track</span> <span class="p">:</span> <span class="kt">Track</span> <span class="c1">-- The track information for convenience</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The train location is a <code class="language-plaintext highlighter-rouge">Maybe TrainLocation</code>. This is a neat trick in Elm and other programming languages to say there could be none. <code class="language-plaintext highlighter-rouge">Maybe</code> is actually a type, and it allows type-safe code without null pointer exceptions. See the <a href="https://guide.elm-lang.org/error_handling/maybe.html">Elm Guide</a> for more information about this. For now, let me say that a variable of type <code class="language-plaintext highlighter-rouge">Maybe someType</code> can contain either <code class="language-plaintext highlighter-rouge">Nothing</code> or <code class="language-plaintext highlighter-rouge">Just something</code>, where <code class="language-plaintext highlighter-rouge">something</code> will be of the type <code class="language-plaintext highlighter-rouge">someType</code> we specified earlier. In other words, a <code class="language-plaintext highlighter-rouge">Maybe Int</code> could be either <code class="language-plaintext highlighter-rouge">Nothing</code> or <code class="language-plaintext highlighter-rouge">Just 5</code> or <code class="language-plaintext highlighter-rouge">Just -37</code> or any other integer wrapped in a <code class="language-plaintext highlighter-rouge">Just</code>. We can use this to implement null-pointer-safe code, as we will see later.</p>
<p>Now, letās reconsider what the <code class="language-plaintext highlighter-rouge">move</code> function did: It simply calculated the new position of a train based on its previous position on the track, depending on its speed and the elapsed time. Now, we need to check if the train is leaving the current track and entering the next one, and handle this transition. In order to do that, we pass the layout into the function, so that we can decide what the next track actually is.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">move</span> <span class="p">:</span> <span class="kt">Layout</span> <span class="o">-></span> <span class="kt">Int</span> <span class="o">-></span> <span class="kt">TrainState</span> <span class="o">-></span> <span class="kt">TrainState</span>
<span class="n">move</span> <span class="n">layout</span> <span class="n">millis</span> <span class="n">trainState</span> <span class="o">=</span>
</code></pre></div></div>
<p>To implement the function, I will write it down in a semi-mathematical way:</p>
<ol>
<li>Create a new train state with the new position after moving, as before.</li>
<li>Pass the new state into a function that will normalize the position by checking if the train is still on the track, and adjusting if necessary.</li>
</ol>
<p><img src="/blog/assets/series/fp-elm/figure-2.svg" alt="Figure 2: Adjusting the train position" /></p>
<p>Here is the code:</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">case</span> <span class="n">trainState</span><span class="o">.</span><span class="n">location</span> <span class="k">of</span>
<span class="kt">Nothing</span> <span class="o">-></span>
<span class="c1">-- If the train has no location, no need to move.</span>
<span class="n">trainState</span>
<span class="kt">Just</span> <span class="n">loc</span> <span class="o">-></span>
<span class="c1">-- Create a new train state ...</span>
<span class="p">{</span> <span class="n">trainState</span>
<span class="c1">-- ... but replace the location with a new location ...</span>
<span class="o">|</span> <span class="n">location</span> <span class="o">=</span>
<span class="c1">-- ... based on the old location but with an updated position ...</span>
<span class="p">{</span> <span class="n">loc</span> <span class="o">|</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">loc</span><span class="o">.</span><span class="n">pos</span> <span class="o">+</span> <span class="n">trainState</span><span class="o">.</span><span class="n">speed</span> <span class="o">*</span> <span class="n">toFloat</span> <span class="n">millis</span> <span class="o">/</span> <span class="mf">1000.0</span> <span class="p">}</span>
<span class="c1">-- and finally "normalize" the location in case we are on a different track now.</span>
<span class="o">|></span> <span class="n">normalizeLocation</span> <span class="n">layout</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">case ... of</code> statement with its two branches <code class="language-plaintext highlighter-rouge">Nothing -></code> and <code class="language-plaintext highlighter-rouge">Just loc -></code> handles the case that the train may not have a valid location. In this case, we are returning the previous train state. If there is a valid location, then we create a new train state based on the previous one.</p>
<p>The <code class="language-plaintext highlighter-rouge">|></code> means āpass the result on into the next function.ā</p>
<p>This is the implementation of <code class="language-plaintext highlighter-rouge">normalizePosition</code>, the function that fixes things when the train enters a new track:</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">normalizeLocation</span> <span class="p">:</span> <span class="kt">Layout</span> <span class="o">-></span> <span class="kt">TrainLocation</span> <span class="o">-></span> <span class="kt">Maybe</span> <span class="kt">TrainLocation</span>
<span class="n">normalizeLocation</span> <span class="n">layout</span> <span class="n">loc</span> <span class="o">=</span>
<span class="c1">-- If the position is beyond the end of the current track ...</span>
<span class="k">if</span> <span class="n">loc</span><span class="o">.</span><span class="n">pos</span> <span class="o">></span> <span class="n">trackLength</span> <span class="n">loc</span><span class="o">.</span><span class="n">track</span> <span class="k">then</span>
<span class="c1">-- ... get the next track.</span>
<span class="k">case</span> <span class="n">nextTrack</span> <span class="n">loc</span><span class="o">.</span><span class="n">edge</span> <span class="n">layout</span> <span class="k">of</span>
<span class="kt">Nothing</span> <span class="o">-></span>
<span class="c1">-- If there is no next track, return.</span>
<span class="kt">Nothing</span>
<span class="kt">Just</span> <span class="p">(</span> <span class="n">otherEdge</span><span class="o">,</span> <span class="n">otherTrack</span> <span class="p">)</span> <span class="o">-></span>
<span class="c1">-- Calculate the new position.</span>
<span class="p">{</span> <span class="n">loc</span>
<span class="c1">-- Subtract the current track length from the position.</span>
<span class="o">|</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">loc</span><span class="o">.</span><span class="n">pos</span> <span class="o">-</span> <span class="n">trackLength</span> <span class="n">loc</span><span class="o">.</span><span class="n">track</span>
<span class="c1">-- Set the edge ...</span>
<span class="o">,</span> <span class="n">edge</span> <span class="o">=</span> <span class="n">otherEdge</span>
<span class="c1">-- ... and track info for the new location.</span>
<span class="o">,</span> <span class="n">track</span> <span class="o">=</span> <span class="n">otherTrack</span>
<span class="p">}</span>
<span class="c1">-- ... and repeat until done.</span>
<span class="o">|></span> <span class="n">normalizeLocation</span> <span class="n">layout</span>
<span class="k">else</span>
<span class="c1">-- We are within the track bounds, so return.</span>
<span class="kt">Just</span> <span class="n">loc</span>
</code></pre></div></div>
<p>If you look closely, it requires a <code class="language-plaintext highlighter-rouge">nextTrack</code> function that returns the next track the train will move on. It will retrieve the next track from the layout graph. The graph library provides some convenient functions, such as <code class="language-plaintext highlighter-rouge">outgoing</code> which gives us a set of edges outgoing from a specific vertex.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">nextTrack</span> <span class="p">:</span> <span class="p">(</span> <span class="kt">Int</span><span class="o">,</span> <span class="kt">Int</span> <span class="p">)</span> <span class="o">-></span> <span class="kt">Layout</span> <span class="o">-></span> <span class="kt">Maybe</span> <span class="p">(</span> <span class="p">(</span> <span class="kt">Int</span><span class="o">,</span> <span class="kt">Int</span> <span class="p">)</span><span class="o">,</span> <span class="kt">Track</span> <span class="p">)</span>
<span class="n">nextTrack</span> <span class="p">(</span> <span class="n">fromId</span><span class="o">,</span> <span class="n">toId</span> <span class="p">)</span> <span class="n">layout</span> <span class="o">=</span>
<span class="kt">Graph</span><span class="o">.</span><span class="n">outgoing</span> <span class="n">toId</span> <span class="n">layout</span>
<span class="o">|></span> <span class="kt">Set</span><span class="o">.</span><span class="n">toList</span>
<span class="c1">-- Arbitrarily select the first track on the list for now.</span>
<span class="o">|></span> <span class="kt">List</span><span class="o">.</span><span class="n">head</span>
<span class="c1">-- If the list was empty, head will return Nothing.</span>
<span class="c1">-- andThen only applies the next function if the input exists.</span>
<span class="c1">-- In this case, create the edge.</span>
<span class="o">|></span> <span class="n">andThen</span> <span class="p">(</span><span class="o">\</span><span class="n">otherId</span> <span class="o">-></span> <span class="kt">Just</span> <span class="p">(</span> <span class="n">toId</span><span class="o">,</span> <span class="n">otherId</span> <span class="p">))</span>
<span class="c1">-- If we are good so far ...</span>
<span class="o">|></span> <span class="n">andThen</span>
<span class="c1">-- ... take the edge we created earlier, ...</span>
<span class="p">(</span><span class="o">\</span><span class="n">edge</span> <span class="o">-></span>
<span class="c1">-- ... and get the Track for this edge.</span>
<span class="k">case</span> <span class="kt">Graph</span><span class="o">.</span><span class="kt">Pair</span><span class="o">.</span><span class="n">getEdgeData</span> <span class="n">edge</span> <span class="n">layout</span> <span class="k">of</span>
<span class="kt">Nothing</span> <span class="o">-></span>
<span class="c1">-- If we don't have track information, return.</span>
<span class="kt">Nothing</span>
<span class="kt">Just</span> <span class="n">track</span> <span class="o">-></span>
<span class="c1">-- If we have it, return the new edge and the Track.</span>
<span class="kt">Just</span> <span class="p">(</span> <span class="n">edge</span><span class="o">,</span> <span class="n">track</span> <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>
<h2 id="next">Next</h2>
<p>We have glossed over the topic of more complex layouts with lines branching off and merging into the mainline. Before we address that, we should first implement curved tracks, so we can add more realism instead of having only a view of what is connected where.</p>
<p>Here is again a simple visualization of the transition from one track to the next, marked in blue and green. Note also the track change in the debug output below.</p>
<div id="train"></div>
<script src="/j/assets/series/fp-elm/main-2.js"></script>
<script>var app = Elm.Main.init({ node: document.getElementById("train") })</script>In the first part of this series, I have talked a little about the functional programming paradigm, and I have shown what a simple simulation of a train moving on an infinite straight track looks like in Elm. But in reality, tracks are not infinite. The branch off each other and merge, and they end somewhere. In this part, I will explore a functional implementation of a train moving from one track to the next.Functional programming with Elm2020-12-19T00:00:00+00:002020-12-19T00:00:00+00:00https://heinecke.com/blog/2020/12/19/functional-programming-with-elm<p>The first time I was exposed to the functional programming paradigm was in Introduction to Programming at university. We used Scheme, a LISP dialect, to explore the structure and interpretation of computer programs. The perspective on programming was rather different from the imperative programming styles I had encountered in BASIC, assembler, Pascal, and C. I thought the style had an elegance, a feeling of neat-ness that I enjoyed. Even though I moved towards the object-oriented field in the coming years, the attraction of the functional paradigm remained.</p>
<p>In recent years, functional programming has experienced a revival as big data analytics, the advent of GPU support for number crunching, and the rise of machine learning have shown its merits. When I discovered that there is a functional language for browser-side code, i.e. a compiler that turns a functional programming language called Elm into JavaScript, I was ready for some exploration.</p>
<h2 id="its-a-train">Itās a train!</h2>
<p>My example will be a train traveling happily along its tracks. In the imperative or object-oriented programming paradigms, you would probably dash ahead an model a <code class="language-plaintext highlighter-rouge">Train</code> class and a <code class="language-plaintext highlighter-rouge">Track</code> class along with the necessary attributes and functions. But in functional programming, the approach is different. It reflects the way mathematicians look at the world, and one important idea is that of <em>immutability</em>. Consider for example the number 9. It is not going to change anytime soon. Or consider a mathematical function like the square root. Its result depends on the number you put into it but not on the point in time you evaluate it. The square root of 9 will always be 3, no matter when you check. This concept of immutability is extremely powerful and mathematicians use it all the time when manipulating formulas. It is also the main difference to the object-oriented style of programming where every object has an identity and a state, which in most cases you can change over time. Not so in functional programming.</p>
<p>Our train is a real world object, although only simulated. It <em>does</em> change state over time. It moves: It changes its position on the track, it might move to another track, it can change its speed and direction, and even its composition as cars get attached and detached. In functional programming, we donāt talk about a train at all. Instead, we talk about its <em>state</em> at a given time. This state will then be the input to some function <code class="language-plaintext highlighter-rouge">move</code>, which returns an entirely different train state. We know that this is the new state of our train, but the program does not care. Its inner mathematician just shrugs their shoulder and says: āI have evaluated your function. Do with the result whatever you please.ā</p>
<p style="margin-left: 3em; margin-right: 3em; padding: 1em; border: 1px solid #81A927; background-color: #C6E979;">In this series of articles I will not focus on the installation of Elm, or how to embed code into a web page like this one. The <a href="https://guide.elm-lang.org/">Elm Guide</a> does an excellent job of that. I will focus on building a tiny toy simulation in Elm instead, because I like trains and because I want to explore functional programming, not html/svg generation.</p>
<p>To define the train state in Elm, I create a record structure and give it a convenient name, a type alias in Elm terminology. By the way, Elm likes to have its code aligned in a somewhat unconventional way, with the comma in front. Also, single line comments are introduced with a double hyphen, <code class="language-plaintext highlighter-rouge">--</code>. Thatās all just optics, Iāll bear with it.</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="k">alias</span> <span class="kt">TrainState</span> <span class="o">=</span>
<span class="p">{</span> <span class="n">name</span> <span class="p">:</span> <span class="kt">String</span> <span class="c1">-- Give the train a nice name.</span>
<span class="o">,</span> <span class="n">length</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- Total length of the train in m.</span>
<span class="o">,</span> <span class="n">speed</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- Speed of the train in m/s.</span>
<span class="o">,</span> <span class="n">trackPosition</span> <span class="p">:</span> <span class="kt">Float</span> <span class="c1">-- Distance from the start of the track in m.</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If we want to simulate the train movement, we need a function that will map a train state (the current state) to a different train state, the future state. How far does the train move? It depends on the elapsed time, so the function will take that as an additional parameter. This is what the function declaration looks like in Elm:</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">move</span> <span class="p">:</span> <span class="kt">Int</span> <span class="o">-></span> <span class="kt">TrainState</span> <span class="o">-></span> <span class="kt">TrainState</span> <span class="c1">-- This is the function declaration.</span>
</code></pre></div></div>
<p>Translated into English: <code class="language-plaintext highlighter-rouge">move</code> is the name of a function that takes an <code class="language-plaintext highlighter-rouge">Int</code> as its parameter and <em>returns a function</em> that takes a <code class="language-plaintext highlighter-rouge">TrainState</code> as its parameter and returns a <code class="language-plaintext highlighter-rouge">TrainState</code>. Fortunately, we donāt have to worry about this complexity yet, although it will come in handy at a later time. If we provide both parameters to the function, Elm is smart enough to call both functions consecutively behind the scenes. For simplicity, letās just say this is a function taking two parameters, the time and the current state, and returns the new state of a train.</p>
<p>This is the implementation of the function:</p>
<div class="language-elm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">move</span> <span class="n">millis</span> <span class="n">state</span> <span class="o">=</span> <span class="c1">-- Naming the two parameters.</span>
<span class="p">{</span> <span class="n">state</span> <span class="c1">-- Shorthand for: Create another record that is exactly like state</span>
<span class="c1">-- ... so we don't have to repeat all the elements that don't change,</span>
<span class="c1">-- ... but with a different value for trackPosition.</span>
<span class="o">|</span> <span class="n">trackPosition</span> <span class="o">=</span> <span class="n">state</span><span class="o">.</span><span class="n">trackPosition</span> <span class="o">+</span> <span class="n">state</span><span class="o">.</span><span class="n">speed</span> <span class="o">*</span> <span class="n">toFloat</span> <span class="n">millis</span> <span class="o">/</span> <span class="mf">1000.0</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There is a bit of Elm syntax that looks unfamiliar. The part in the curly braces is a shorthand way to create a new record that is the same as some other record, with a few variations. The function <code class="language-plaintext highlighter-rouge">move</code> with its two parameters <code class="language-plaintext highlighter-rouge">millis</code> (the elapsed time in milliseconds) and <code class="language-plaintext highlighter-rouge">state</code> (the previous state of the train) returns a new train state that is the same as before, <em>except</em> that the <code class="language-plaintext highlighter-rouge">trackPosition</code> of the new state will be calculated with the given formula.</p>
<p>Note again that this does not change the train state itself; it creates a new one. The Elm notation is just a convenient shorthand so that we donāt have to write out initializations for all the elements of the data structure that are the same. If you wanted, you could keep the old train state around, for example to implement an instant replay function in your simulator.</p>
<p>Try this in the Elm interactive interpreter:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">></span><span class="w"> </span><span class="nb">type alias </span>TrainState <span class="o">=</span>
<span class="go">| { name : String
| , length : Float
| , speed : Float
| , trackPosition : Float
| }
</span><span class="gp">></span><span class="w"> </span>move : Int -> TrainState -> TrainState
<span class="go">| move millis previous =
| { previous
| | trackPosition = previous.trackPosition
| + previous.speed * toFloat millis / 1000.0
| }
</span><span class="gp">></span><span class="w"> </span>myTrain <span class="o">=</span>
<span class="go">| { name = "Happy Train"
| , length = 30.0
| , speed = 10.0
| , trackPosition = 40.0 }
{ length = 30, name = "Happy Train", speed = 10, trackPosition = 40 }
: { length : Float, name : String, speed : Float, trackPosition : Float }
</span><span class="gp">></span><span class="w"> </span>move 1000 myTrain
<span class="go">{ length = 30, name = "Happy Train", speed = 10, trackPosition = 50 }
: TrainState
</span><span class="gp">></span><span class="w"> </span>myTrain
<span class="go">{ length = 30, name = "Happy Train", speed = 10, trackPosition = 40 }
: { length : Float, name : String, speed : Float, trackPosition : Float }
</span></code></pre></div></div>
<p>If you look at the results of the two last calls, the result of the move has a new track position, according to time and speed, but the variable <code class="language-plaintext highlighter-rouge">myTrain</code> still holds the old, unchanged train state. In functional programming, things never change. But of course, if we wanted we could assign the new state to the name <code class="language-plaintext highlighter-rouge">myTrain</code>.</p>
<h2 id="next">Next</h2>
<p>In the next article, I will explore how to represent a track layout and how to implement movement from one track to the next.</p>
<p>And here is a very simple visualization of the simulation written in Elm. If nothing is moving, you have missed the train. Just click the reset button.</p>
<div id="train"></div>
<script src="/j/assets/series/fp-elm/main-1.js"></script>
<script>var app = Elm.Main.init({ node: document.getElementById("train") })</script>The first time I was exposed to the functional programming paradigm was in Introduction to Programming at university. We used Scheme, a LISP dialect, to explore the structure and interpretation of computer programs. The perspective on programming was rather different from the imperative programming styles I had encountered in BASIC, assembler, Pascal, and C. I thought the style had an elegance, a feeling of neat-ness that I enjoyed. Even though I moved towards the object-oriented field in the coming years, the attraction of the functional paradigm remained.Starting over with Jekyll2020-12-16T00:00:00+00:002020-12-16T00:00:00+00:00https://heinecke.com/blog/2020/12/16/starting-over-with-jekyll<p>It seems every year around this time, I consider reviving my personal web page.
Why I do this, I have no clue. I guess it is because I do not entirely trust
social networks and also because there are so many of them. Or it is because I
like to maintain at least some control by providing my own information hub about
myself. Or perhaps it is simply to try out things.</p>
<p>Whatever the reason, this is the latest iteration.</p>
<p>Iām not too worried with formatting, so Iām starting out with the Minima theme
with only small modifications. Itās also a good opportunity to re-familiarize
myself with <a href="https://github.com/features/actions">GitHub Actions</a>. A simple
workflow is now building the site and deploying it. Thanks to lemonarcās <a href="https://github.com/marketplace/actions/jekyll-action">Jekyll
action</a> and Kevin
Painchaudās
<a href="https://github.com/marketplace/actions/simple-ftp-deploy">simple-ftp-deploy-action</a>,
as well as of course the Jekyll maintainers. Itās a really neat and slim tool
for creating static web sites like this one.</p>It seems every year around this time, I consider reviving my personal web page. Why I do this, I have no clue. I guess it is because I do not entirely trust social networks and also because there are so many of them. Or it is because I like to maintain at least some control by providing my own information hub about myself. Or perhaps it is simply to try out things.Kubernetes on Raspberry Pi reloaded2020-12-12T00:00:00+00:002020-12-12T00:00:00+00:00https://heinecke.com/blog/2020/12/12/kubernetes-on-raspberry-pi<p>Rediscovering my old <a href="https://www.raspberrypi.org/">Raspberry Pi</a> cluster and running a <a href="https://kubernetes.io/">Kubernetes</a> cluster on it was a nice Saturday project. It was pretty straight-forward, especially as the hardware was already set up: Four Raspberry Pi 3 devices, a USB powered 4-port LAN router (plus uplink), and an Anker 5 port USB power supply. This setup allows for fast and self-contained local communication within the cluster that does not spill internal packets into the rest of the network, and it is very portable.</p>
<p>I have set up Kubernetes clusters before but it is surprising how much one unlearns when you do not do it for a year or so. So I flashed a brand new version of Raspbian and followed <a href="https://alexellisuk.medium.com/walk-through-install-kubernetes-to-your-raspberry-pi-in-15-minutes-84a8492dc95a">the instructions of Alex Ellis on Medium</a>. This worked like a breeze apart from some minor troubles when connecting to the Pis from Windows.</p>
<p><img src="/j/assets/img/raspberry_pi_cluster.png" alt="Raspberry Pi cluster" class="centered" /></p>
<p>Things left for upcoming weekends:</p>
<ul>
<li>Set up proper cluster-internal routing with a private host network.</li>
<li>Consider persistence of some sort. I have experimented with Persistent Volume Claims and GlusterFS before but frankly, I donāt think it is the route I want to take. For fast non-persistent storage, the SD cards are enough. If I ever want additional bulk storage, I will probably go with an attached SSD drive. For database services, well, thatās for another day.</li>
<li>Moving some real tasks on the cluster. So far it is no more than a proof of concept.</li>
</ul>Rediscovering my old Raspberry Pi cluster and running a Kubernetes cluster on it was a nice Saturday project. It was pretty straight-forward, especially as the hardware was already set up: Four Raspberry Pi 3 devices, a USB powered 4-port LAN router (plus uplink), and an Anker 5 port USB power supply. This setup allows for fast and self-contained local communication within the cluster that does not spill internal packets into the rest of the network, and it is very portable.