<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Héctor Ramón</title>
    <description>The latest articles on Forem by Héctor Ramón (@hecrj).</description>
    <link>https://forem.com/hecrj</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F72132%2Fc2ff4967-a741-4216-8023-3905b153bbec.jpg</url>
      <title>Forem: Héctor Ramón</title>
      <link>https://forem.com/hecrj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/hecrj"/>
    <language>en</language>
    <item>
      <title>Coffee - An opinionated 2D game engine for Rust</title>
      <dc:creator>Héctor Ramón</dc:creator>
      <pubDate>Sun, 28 Apr 2019 15:30:09 +0000</pubDate>
      <link>https://forem.com/hecrj/coffee-an-opinionated-2d-game-engine-for-rust-3bbl</link>
      <guid>https://forem.com/hecrj/coffee-an-opinionated-2d-game-engine-for-rust-3bbl</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/hecrj/coffee" rel="noopener noreferrer"&gt;Coffee&lt;/a&gt; is an opinionated 2D game engine for Rust focused on simplicity, explicitness, and type-safety.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Coffee is in a very early stage of development.&lt;/strong&gt; Active development is&lt;br&gt;
planned during 2019 (and hopefully beyond that!). Many &lt;a href="https://github.com/hecrj/coffee/issues?q=is%3Aissue+is%3Aopen+label%3Afeature" rel="noopener noreferrer"&gt;basic features are still&lt;br&gt;
missing&lt;/a&gt;, some &lt;a href="https://github.com/hecrj/coffee#implementation-details" rel="noopener noreferrer"&gt;dependencies are experimental&lt;/a&gt;, and there are probably &lt;em&gt;many&lt;/em&gt;&lt;br&gt;
bugs. &lt;a href="https://github.com/hecrj/coffee#contributing--feedback" rel="noopener noreferrer"&gt;Feel free to contribute!&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Declarative, type-safe asset loading&lt;/li&gt;
&lt;li&gt;Loading screens with progress tracking&lt;/li&gt;
&lt;li&gt;Built-in &lt;a href="https://github.com/hecrj/coffee/blob/master/images/debug.png" rel="noopener noreferrer"&gt;debug view with performance metrics&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed timestep&lt;/li&gt;
&lt;li&gt;Explicit, easy to use, hardware-accelerated 2D graphics API&lt;/li&gt;
&lt;li&gt;Multiplatform support leveraging OpenGL, Vulkan, Metal, D3D11, and D3D12&lt;/li&gt;
&lt;li&gt;Texture array support&lt;/li&gt;
&lt;li&gt;Explicit and efficient batched draws&lt;/li&gt;
&lt;li&gt;Off-screen rendering&lt;/li&gt;
&lt;li&gt;TrueType font rendering&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Here is a minimal example that will open a window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;coffee&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Game&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timer&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;coffee&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;graphics&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WindowSettings&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;MyGame&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WindowSettings&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A caffeinated game"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1280&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;resizable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your game state goes here...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Game&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;View&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// No view data.&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// No input data.&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TICKS_PER_SECOND&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u16&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Update rate&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyGame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load your game assets here. Check out the `load` module!&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Update your game here&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_timer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Timer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Clear the current frame&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="nf"&gt;.frame&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="nf"&gt;.clear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BLACK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Draw your game here. Check out the `graphics` module!&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;p&gt;If you want to know more, check out the repository on GitHub!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/hecrj" rel="noopener noreferrer"&gt;
        hecrj
      &lt;/a&gt; / &lt;a href="https://github.com/hecrj/coffee" rel="noopener noreferrer"&gt;
        coffee
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An opinionated 2D game engine for Rust
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Coffee&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/hecrj/coffee/actions" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/hecrj/coffee/workflows/Integration/badge.svg" alt="Integration status"&gt;&lt;/a&gt;
&lt;a href="https://docs.rs/coffee" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1dd9efad17a6bc55056b828fc7f748a00056ff44e724274eab734615c6d549b9/68747470733a2f2f646f63732e72732f636f666665652f62616467652e737667" alt="Documentation"&gt;&lt;/a&gt;
&lt;a href="https://crates.io/crates/coffee" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9820cf6f57d19868ef95a49e642c513380f34b0b16e9a6b375182e47ff9937bf/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f762f636f666665652e737667" alt="Crates.io"&gt;&lt;/a&gt;
&lt;a href="https://github.com/hecrj/coffee/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a0342f284acd3bea11e849cf6c5125ca415e8c5516248c708948bbe150047412/68747470733a2f2f696d672e736869656c64732e696f2f6372617465732f6c2f636f666665652e737667" alt="License"&gt;&lt;/a&gt;
&lt;a href="https://gitter.im/hecrj/coffee" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/990aec8fc70910985e65779f663979a78f7d94ca71dd12a6211a5147ac49c02a/68747470733a2f2f6261646765732e6769747465722e696d2f686563726a2f636f666665652e706e67" alt="Gitter chat"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An opinionated 2D game engine for Rust focused on simplicity, explicitness, and type-safety.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Coffee is in a very early stage of development.&lt;/strong&gt; Many &lt;a href="https://github.com/hecrj/coffee/issues?q=is%3Aissue+is%3Aopen+label%3Afeature" rel="noopener noreferrer"&gt;basic features are still missing&lt;/a&gt;, some &lt;a href="https://github.com/hecrj/coffee#implementation-details" rel="noopener noreferrer"&gt;dependencies are experimental&lt;/a&gt;, and there are probably &lt;em&gt;many&lt;/em&gt; bugs. &lt;a href="https://github.com/hecrj/coffee#contributing--feedback" rel="noopener noreferrer"&gt;Feel free to contribute!&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gfycat.com/gloomyweakhammerheadshark" rel="nofollow noopener noreferrer"&gt;Responsive, customizable GUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Declarative, type-safe loading screens with progress tracking&lt;/li&gt;
&lt;li&gt;Built-in &lt;a href="https://github.com/hecrj/coffee/blob/master/images/debug.png" rel="noopener noreferrer"&gt;debug view with performance metrics&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fixed, deterministic timestep&lt;/li&gt;
&lt;li&gt;Explicit, easy to use, hardware-accelerated 2D graphics API&lt;/li&gt;
&lt;li&gt;Multiplatform support leveraging OpenGL, Vulkan, Metal, D3D11, and D3D12&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gfycat.com/beautifulseparatebeetle" rel="nofollow noopener noreferrer"&gt;Explicit and efficient batched draws&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gfycat.com/academicglossykingfisher" rel="nofollow noopener noreferrer"&gt;Mesh support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Texture array support&lt;/li&gt;
&lt;li&gt;Off-screen rendering&lt;/li&gt;
&lt;li&gt;TrueType font rendering&lt;/li&gt;
&lt;li&gt;Gamepad support&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And more! Check out the &lt;a href="https://github.com/hecrj/coffee/tree/master/examples" rel="noopener noreferrer"&gt;examples&lt;/a&gt; to see them in action.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Add &lt;code&gt;coffee&lt;/code&gt; as a dependency in your &lt;code&gt;Cargo.toml&lt;/code&gt; and enable a graphics backend
feature (&lt;code&gt;opengl&lt;/code&gt;, &lt;code&gt;vulkan&lt;/code&gt;, &lt;code&gt;metal&lt;/code&gt;, &lt;code&gt;dx11&lt;/code&gt;, or &lt;code&gt;dx12&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight highlight-source-toml notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-smi"&gt;coffee&lt;/span&gt; = { &lt;span class="pl-smi"&gt;version&lt;/span&gt; = &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;0.4&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-smi"&gt;features&lt;/span&gt; = [&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/hecrj/coffee" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>rust</category>
      <category>gamedev</category>
      <category>showdev</category>
      <category>graphics</category>
    </item>
    <item>
      <title>Stop coupling logic with your HTTP layer!</title>
      <dc:creator>Héctor Ramón</dc:creator>
      <pubDate>Tue, 30 Oct 2018 19:11:41 +0000</pubDate>
      <link>https://forem.com/hecrj/stop-coupling-logic-with-your-http-layer-163</link>
      <guid>https://forem.com/hecrj/stop-coupling-logic-with-your-http-layer-163</guid>
      <description>&lt;p&gt;As a developer, there is one issue that I tend to notice in many codebases: &lt;strong&gt;logic coupled with a specific communication layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This issue is especially common in the &lt;strong&gt;controllers&lt;/strong&gt; of most web backends, where application logic is usually intertwined with access to the HTTP layer. It is not surprising. Many documentation examples of some of the most well-known frameworks (&lt;a href="https://guides.rubyonrails.org/action_controller_overview.html#parameters" rel="noopener noreferrer"&gt;Rails&lt;/a&gt;, &lt;a href="https://docs.djangoproject.com/en/2.1/intro/tutorial03/" rel="noopener noreferrer"&gt;Django&lt;/a&gt;, &lt;a href="http://flask.pocoo.org/docs/1.0/quickstart/#a-minimal-application" rel="noopener noreferrer"&gt;Flask&lt;/a&gt;, &lt;a href="https://hexdocs.pm/phoenix/overview.html" rel="noopener noreferrer"&gt;Phoenix&lt;/a&gt;, etc.) have this issue.&lt;/p&gt;

&lt;p&gt;But, what do I mean when I say "logic intertwined with access to the HTTP layer"? Let's take a look at how a simple login endpoint could be implemented in Ruby on Rails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password_match?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:invalid_credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;json_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;auth_token: &lt;/span&gt;&lt;span class="no"&gt;Tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, right? But... How do we use this &lt;code&gt;UsersController&lt;/code&gt; class? How do we test our &lt;code&gt;login&lt;/code&gt; logic? Who populates &lt;code&gt;params&lt;/code&gt;? What data does it need? &lt;strong&gt;The public contract of this code is not clear at all!&lt;/strong&gt; We have a class with a method that takes no arguments and uses internal (hidden) state to do its job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When code cannot be easily used in isolation, it becomes harder to understand, test and debug.&lt;/strong&gt; We should try to avoid it as much as possible.&lt;/p&gt;

&lt;p&gt;The code above is tying the logic of the function to some specific communication layer (HTTP, in this case). Using &lt;code&gt;params&lt;/code&gt; and &lt;code&gt;json_response&lt;/code&gt; forces us to be aware of this layer every time that we want to use this &lt;code&gt;login&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;We can isolate the logic of our endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ApiLogin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:invalid_credentials&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password_match?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;auth_token: &lt;/span&gt;&lt;span class="no"&gt;Tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is now a communication-agnostic function. Its input  (&lt;code&gt;email&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt;) and its output (a simple hash with &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;errors&lt;/code&gt;) are explicit. Therefore, we can test it very easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ApiLogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="s2"&gt;"some@email.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"12345678"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; { data: { auth_token: "..." }, errors: [] }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we just need to connect this function to our communication layer. We can use an &lt;code&gt;ApplicationController&lt;/code&gt;, like before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ApiLogin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt;
      &lt;span class="n"&gt;json_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;error_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key point here is that this wiring does not contain any relevant logic that needs specific testing because it can be easily abstracted! Most of the time, connecting a function to an HTTP layer consists of the same steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Obtain the input data from the request.&lt;/li&gt;
&lt;li&gt;Call a function with the obtained data.&lt;/li&gt;
&lt;li&gt;Transform the output of the function into an HTTP response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this in mind, we could write a Ruby DSL to produce custom controllers, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;UsersController&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;controller&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="ss"&gt;:login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ApiLogin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;email: &lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And extend it as needed. For instance, we could implement &lt;code&gt;header&lt;/code&gt; and &lt;code&gt;json&lt;/code&gt; methods, analogous to &lt;code&gt;param&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are many ways to expose a function over HTTP. I personally like to build a pipeline of transformations where the input is the HTTP request and the output is the HTTP response, especially in functional languages with powerful type systems. This pipeline is defined safely and accurately step by step with a flexible API. I will write about how I did this in Haskell soon!&lt;/p&gt;

&lt;p&gt;In conclusion, once we split logic from communication, we obtain some interesting benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our application logic becomes easier to use, understand and test.&lt;/li&gt;
&lt;li&gt;The communication details can be centralized, changed and tested using a single-responsibility abstraction.&lt;/li&gt;
&lt;li&gt;We can implement a new communication layer (a CLI, a different HTTP layer) to expose the same logic.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Let me know about your thoughts in the comments! Why do you think it's such a common issue? Are you already doing something similar?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Use opaque types in Elm!</title>
      <dc:creator>Héctor Ramón</dc:creator>
      <pubDate>Sat, 27 Oct 2018 17:40:04 +0000</pubDate>
      <link>https://forem.com/hecrj/use-opaque-types-in-elm-3oal</link>
      <guid>https://forem.com/hecrj/use-opaque-types-in-elm-3oal</guid>
      <description>&lt;p&gt;It's been a while since I joined the &lt;a href="https://elmlang.herokuapp.com/" rel="noopener noreferrer"&gt;Elm Slack&lt;/a&gt;. During this time, I have seen different folks ask how, and when, to use &lt;strong&gt;opaque types&lt;/strong&gt;. I have also seen many codebases and examples where opaque types were non-existent.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F2ks3pk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgflip.com%2F2ks3pk.jpg" alt="Strings, strings everywhere"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think opaque types are extremely important when it comes to API design in Elm and I suspect they are not used nearly enough. In this article we will learn how opaque types can &lt;strong&gt;glue&lt;/strong&gt; an API together while making our code &lt;strong&gt;self-documenting&lt;/strong&gt; and &lt;strong&gt;bug-free&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  A common scenario
&lt;/h1&gt;

&lt;p&gt;We will work with an example of what I think is a fairly common scenario: a form that validates and submits some data to create a new resource remotely. This kind of interaction is the core of many interactive web applications.&lt;/p&gt;

&lt;p&gt;For simplicity, we will assume the resource we want to create is a very simple &lt;strong&gt;question&lt;/strong&gt; with a title and a body.&lt;/p&gt;

&lt;p&gt;First, we will start with code that does not use any opaque types. Then, we will be gradually adding them and analyzing how code has improved along the way!&lt;/p&gt;

&lt;p&gt;Let's begin!&lt;/p&gt;

&lt;h1&gt;
  
  
  An example with primitives
&lt;/h1&gt;

&lt;p&gt;We want to create a &lt;strong&gt;question&lt;/strong&gt;. Let's say we write a module &lt;code&gt;Question&lt;/code&gt; with this API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;create&lt;/code&gt; function takes a question &lt;code&gt;title&lt;/code&gt; and a &lt;code&gt;body&lt;/code&gt; and returns a &lt;code&gt;Task&lt;/code&gt; which tries to create the appropriate question. This &lt;code&gt;Task&lt;/code&gt; can either fail and return an &lt;code&gt;Http.Error&lt;/code&gt;, or succeed and return a &lt;code&gt;String&lt;/code&gt; representing the &lt;code&gt;slug&lt;/code&gt; of the brand new question.&lt;/p&gt;

&lt;p&gt;Then, we build a form so our users can create questions. We will focus on the code that submits the form, leaving out some irrelevant details like how the fields are updated/rendered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="c1"&gt;--  , ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Submit&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kt"&gt;QuestionCreated&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Result&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;--  | ...&lt;/span&gt;

&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
        &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
            &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
                &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="kt"&gt;QuestionCreated&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;-- ...&lt;/span&gt;

&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Html&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
&lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;form&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;onSubmit&lt;/span&gt; &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;titleField&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
      &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyField&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
      &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;submitButton&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do you notice any issues here? Let's see. What happens when we &lt;code&gt;Submit&lt;/code&gt; our form? We create the question using &lt;code&gt;Question.create&lt;/code&gt;. Sounds good! But wait... Where is validation?! What happens if &lt;code&gt;model.title&lt;/code&gt; is empty? What if &lt;code&gt;model.body&lt;/code&gt; is extremely long? Hmm... Okay, no problem. We just need to add an if-then-else, right?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleIsValid&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bodyIsValid&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
            &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
                &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="kt"&gt;QuestionCreated&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool! We are done here. The new &lt;code&gt;titleIsValid&lt;/code&gt; and &lt;code&gt;bodyIsValid&lt;/code&gt; functions deal with validation and there is no way to create an invalid question now.&lt;/p&gt;

&lt;p&gt;However, doesn't this feel a bit off? Whenever we want to use &lt;code&gt;create&lt;/code&gt; we have to &lt;strong&gt;remember&lt;/strong&gt; to validate its input by using &lt;code&gt;titleIsValid&lt;/code&gt; and &lt;code&gt;bodyIsValid&lt;/code&gt;. What if some requirements change and &lt;code&gt;create&lt;/code&gt; needs another argument? We will have to &lt;strong&gt;remember&lt;/strong&gt; to update the if-then-else. What if some new developer reads the type signature of &lt;code&gt;create&lt;/code&gt; and decides to use it somewhere else without any kind of validation? Not desirable.&lt;/p&gt;

&lt;p&gt;In the end, our API is error-prone. &lt;strong&gt;It can be used incorrectly&lt;/strong&gt;. Can we do better? Wouldn't it be nice if we could somehow tie the concept of validating and creating a question together?&lt;/p&gt;

&lt;h1&gt;
  
  
  Opaque types to the rescue!
&lt;/h1&gt;

&lt;p&gt;Before we continue, let's review what an opaque type is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An opaque type is a custom type without exposed constructors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, but if the constructors are not exposed... How do we use an opaque type? Well, the constructors are accessible internally, in the module where the custom type has been defined. Therefore, we can expose functions to &lt;em&gt;control&lt;/em&gt; how the values of the opaque type are created.&lt;/p&gt;

&lt;p&gt;Let's see how this works! Going back to our &lt;code&gt;Question&lt;/code&gt; module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue with &lt;code&gt;create&lt;/code&gt; is that the types of its arguments accept invalid domain values. For instance, &lt;code&gt;""&lt;/code&gt; is a perfectly valid &lt;code&gt;String&lt;/code&gt; but it is not a valid question title.&lt;/p&gt;

&lt;p&gt;Can we create a new custom type where its possible values are always valid question titles? Let's see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;titleFromString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

&lt;span class="n"&gt;titleFromString&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Result&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt;
&lt;span class="n"&gt;titleFromString&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="kt"&gt;Err&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the title must not be less than 5 characters long"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="kt"&gt;Err&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the title must not be more than 100 characters long"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Here we define a new custom type &lt;code&gt;Title&lt;/code&gt; without exposing its constructor. Instead, we implement a &lt;code&gt;titleFromString&lt;/code&gt; function which takes a &lt;code&gt;String&lt;/code&gt; and returns either a &lt;code&gt;String&lt;/code&gt; describing an error when validation fails, or a &lt;code&gt;Title&lt;/code&gt; when validation succeeds.&lt;/p&gt;

&lt;p&gt;The only way to build a &lt;code&gt;Title&lt;/code&gt; is to use &lt;code&gt;titleFromString&lt;/code&gt;. As a consequence, if we have a &lt;code&gt;Title&lt;/code&gt; anywhere in our codebase, we can be confident that it is a valid question title. The &lt;code&gt;Title&lt;/code&gt; type &lt;strong&gt;guarantees validity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Whenever we are validating data, we are just checking that the data has some &lt;strong&gt;guarantees&lt;/strong&gt;. Performing validation and then using the same type afterwards is a missed opportunity! We should try to capture these guarantees using opaque types. As a result, our APIs will become safer and easier to understand.&lt;/p&gt;

&lt;p&gt;Similarly, we can define a &lt;code&gt;Body&lt;/code&gt; type. Then, we can update the &lt;code&gt;create&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt; &lt;span class="k"&gt;exposing&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bodyFromString&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;titleFromString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;-- type Title ...&lt;/span&gt;
&lt;span class="c1"&gt;-- type Body ...&lt;/span&gt;

&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;create&lt;/code&gt; function forces us to provide a valid title and a valid body. We cannot longer submit the form as we did before. We must use &lt;code&gt;titleFromString&lt;/code&gt; and &lt;code&gt;bodyFromString&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleFromString&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bodyFromString&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Ok&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="c1"&gt;-- Validation succeded&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
                &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
                    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="kt"&gt;QuestionCreated&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="c1"&gt;-- Validation failed&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;none&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our API does not provide any other way to do this. We cannot skip validation anymore! We do not even need to &lt;strong&gt;remember&lt;/strong&gt; validation. The API &lt;strong&gt;forces&lt;/strong&gt; us to deal with errors along the way. Our API is &lt;strong&gt;safer&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Further improvements
&lt;/h1&gt;

&lt;p&gt;We are not done yet! There are still a couple of things we can improve.&lt;/p&gt;

&lt;p&gt;The first improvement has to do with &lt;strong&gt;duplicated validation&lt;/strong&gt;. We are currently performing validation in our &lt;code&gt;update&lt;/code&gt; function when the form is submitted, but we probably want to validate the form fields in our &lt;code&gt;view&lt;/code&gt; code too, maybe show error messages in real time. Therefore, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;view&lt;/code&gt; are both using &lt;code&gt;titleFromString&lt;/code&gt; and &lt;code&gt;bodyFromString&lt;/code&gt;: &lt;code&gt;update&lt;/code&gt; only cares about the successful result, while &lt;code&gt;view&lt;/code&gt; only cares about the errors.&lt;/p&gt;

&lt;p&gt;Now that we have &lt;code&gt;Title&lt;/code&gt; and &lt;code&gt;Body&lt;/code&gt; types, we can make our &lt;code&gt;Submit&lt;/code&gt; message &lt;strong&gt;impossible to be fired if the form values are invalid&lt;/strong&gt;, validating only once in &lt;code&gt;view&lt;/code&gt; and propagating the &lt;strong&gt;validation guarantees&lt;/strong&gt; over to &lt;code&gt;update&lt;/code&gt;. We just need to change the &lt;code&gt;Submit&lt;/code&gt; message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Msg&lt;/span&gt;
    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Body&lt;/span&gt;
    &lt;span class="c1"&gt;-- |...&lt;/span&gt;


&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;
    &lt;span class="kt"&gt;Submit&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
        &lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
            &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="kt"&gt;QuestionCreated&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;-- ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean! We got rid of the awkward no-operation in the else clause when validation failed.&lt;/p&gt;

&lt;p&gt;This particular approach, where form validation happens in &lt;code&gt;view&lt;/code&gt; while capturing guarantees using opaque types, is one of the main ideas behind a package that I wrote: &lt;a href="https://github.com/hecrj/composable-form" rel="noopener noreferrer"&gt;&lt;code&gt;composable-form&lt;/code&gt;&lt;/a&gt;. &lt;a href="https://github.com/hecrj/composable-form" rel="noopener noreferrer"&gt;&lt;code&gt;composable-form&lt;/code&gt;&lt;/a&gt; treats forms as composable units, so they can be built, combined, and reused freely. I will write about it soon!&lt;/p&gt;

&lt;p&gt;The second improvement is simple. We can create a &lt;code&gt;Slug&lt;/code&gt; opaque type. Then, the &lt;code&gt;create&lt;/code&gt; function will look even better:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;Slug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we ever need to allow our users to edit questions, we could just write an &lt;code&gt;edit&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elm"&gt;&lt;code&gt;&lt;span class="n"&gt;edit&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Slug&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Body&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Task&lt;/span&gt; &lt;span class="kt"&gt;Http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Error&lt;/span&gt; &lt;span class="kt"&gt;Slug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neat! Our API will explicitly say a question can only be edited if it has been previously created.&lt;/p&gt;

&lt;h1&gt;
  
  
  In summary
&lt;/h1&gt;

&lt;p&gt;Opaque types not only make your code safer, but they can also be used to connect different concepts together, making your codebase much &lt;strong&gt;easier to understand&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is one exercise I like to perform when I code: I try to imagine the thought process that a new developer, with a specific goal in mind, will have when reading the module documentation. Let's do that with our &lt;code&gt;Question&lt;/code&gt; module, assuming Bob wants to find out how to &lt;code&gt;create&lt;/code&gt; a new question:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bob finds a &lt;code&gt;create&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;Bob sees he can &lt;code&gt;create&lt;/code&gt; a question if he provides a &lt;code&gt;Title&lt;/code&gt; and a &lt;code&gt;Body&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bob wonders if there is some way to build these using a &lt;code&gt;String&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bob finds &lt;code&gt;titleFromString&lt;/code&gt; and &lt;code&gt;bodyFromString&lt;/code&gt;, which seem to do the job.&lt;/li&gt;
&lt;li&gt;Bob notices those functions return a &lt;code&gt;Result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Bob understands he will need to handle the case where the provided &lt;code&gt;String&lt;/code&gt; is not valid.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this case, the developer can get a clear understanding of the &lt;code&gt;Question&lt;/code&gt; API just by looking at the type signatures. No comments needed!&lt;/p&gt;




&lt;p&gt;This is it for now! I will write more about Elm soon.&lt;/p&gt;

&lt;p&gt;I would like to hear about your thoughts on opaque types and form validation, so do not hesitate to comment! You can also find me (&lt;a class="mentioned-user" href="https://dev.to/hecrj"&gt;@hecrj&lt;/a&gt;) in the &lt;a href="https://elmlang.herokuapp.com/" rel="noopener noreferrer"&gt;Elm Slack&lt;/a&gt;, I am always happy to talk.&lt;/p&gt;

</description>
      <category>elm</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
