Elixir, etc. - A Brief Look at Pete's Alley

Written by Rich Morin.

Contents: (hide) (show)

Path:  AreasContentOverviews

Precis:  slides for a lightning talk on Pete's Alley

Here are some slides I prepared in November 2019 for a proposed lightning talk on Pete’s Alley.

Index

Slides

(hide) (show)

<h4>Title</h4> <h4>A Brief Look at Pete’s Alley</h4> <p>by Rich Morin (rdm@cfcl.com)<br> Canta Forda Computer Laboratory</p> <p>Erlang &amp; Elixir SF<br> November 19, 2019</p> <h4>Background</h4> <p>Pete’s Alley isn’t really a “production” Elixir project:</p> <ul> <li>It’s my first “real” project in Elixir and Phoenix. </li> <li>It’s largely a design and implementation testbed. </li> <li>After a year and 33 KLOC, it’s still a prototype. </li> </ul> <p>So, I’m free to try some unusual approaches. (YMMV!)</p> <h4>Approaches</h4> <ul> <li>Keep the input data convenient to edit and use. </li> <li>Keep the output styling spare and accessible. </li> <li>Keep the edited files small(ish) and cohesive.<br><br> </li> <li>Use <code class="inline">@doc</code>, <code class="inline">@moduledoc</code>, and <code class="inline">@spec</code> pervasively. </li> <li>Prefer doctests over separate test modules. </li> <li>Do lots of automated checks on code and data. </li> </ul> <h4>Data Storage</h4> <p>Why I don’t use Ecto:</p> <ul> <li>This is a read-mostly application. </li> <li>The amount of data is pretty small. </li> <li>Ecto brings in a lot of complexity. </li> <li>The relational model isn’t a good fit. </li> </ul> <p>What I do, instead:</p> <ul> <li>Load input files into a tree of maps. </li> <li>Build some index data structures. </li> <li>Store and access all this via actors. </li> <li>Code up search logic (etc), as needed. </li> </ul> <h4>Input Files</h4> <ul> <li>TOML works well for semi-structured metadata. </li> <li>Markdown works well for simple, formatted text. </li> <li>So, I use TOML, with some embedded Markdown.<br><br> </li> <li>The combination is convenient and very flexible. </li> <li>It’s also accessible for visually impaired users. </li> <li>A few extensions make it even more convenient. </li> </ul> <h4>Extensions</h4> <p>Make it easier to enter lists of items in TOML:</p> <pre><code>&#39;free, GPL, open source&#39; [ &#39;free&#39;, &#39;GPL&#39;, &#39;open source&#39; ]</code></pre> <p>Make it easier to link to web sites in Markdown:</p> <pre><code>[TOML]{ext_wp|TOML} -&gt; [TOML](https://en.wikipedia.org/wiki/TOML) [$url]{http://foo.com/bar} -&gt; [http://foo.com/bar](http://foo.com/bar)</code></pre> <h4>App Layout</h4> <p>Per Dave Thomas, I separate interfaces and implementations:</p> <pre><code>.../apps/foo/lib/ | foo/ | | _foo_t.ex # Foo.Types (@type, @typedoc, typep, ...) | | bar.ex # Foo.Bar (@doc, @spec, def, defp, ...) | | ... | foo.ex # Foo (@doc, defdelegate, ...)</code></pre> <p>This makes the code much easier to read and maintain:</p> <ul> <li>Files are smaller, so they are easier to read and safer to edit. </li> <li>Modules are also smaller, less coupled, and more cohesive. </li> <li>Implementation functions and modules can be documented. </li> </ul> <h4>Code Format</h4> <ul> <li><code class="inline">mix format</code> makes sense for large teams. </li> <li>For personal projects, it’s mostly a burden. </li> </ul> <p>The biggest problem is the ban on in-line spacing:</p> <pre><code>item_keys = ref_map # %{ foo: &quot;a|b, ...&quot; } |&gt; Enum.map(fields_fn) # [ [ &quot;a|b&quot;, &quot;c|d&quot;, ... ], ... ] |&gt; List.flatten() # [ &quot;a|b&quot;, &quot;c|d&quot;, ... ] ... @type kv_info :: %{ :kv_cnts =&gt; kv_cnts, # %{ &lt;key&gt;: &lt;count&gt; } :kv_descs =&gt; kv_descs, # %{ &lt;key&gt;: &lt;desc&gt; } ... }</code></pre> <h4>Comments</h4> <p>Comments can be used strategically:</p> <ul> <li>Include a partial path at the top of each file. </li> <li>Include a TOC at the top of each code file. </li> <li>Define and use semantic flags (e.g., <code class="inline">#!T</code>).<br><br> </li> <li>Describe each part of multi-line literals. </li> <li>Describe data flow in multi-line pipelines. </li> <li>Describe private functions, macros, etc. </li> </ul>