<?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>DEV Community: Angelo Lakra</title>
    <description>The latest articles on DEV Community by Angelo Lakra (@alakra).</description>
    <link>https://dev.to/alakra</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%2F96925%2F3e8843d3-fea2-4056-9aa2-46b4c29ef96b.jpg</url>
      <title>DEV Community: Angelo Lakra</title>
      <link>https://dev.to/alakra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alakra"/>
    <language>en</language>
    <item>
      <title>Dropping CSS frameworks for Grid and Flexbox</title>
      <dc:creator>Angelo Lakra</dc:creator>
      <pubDate>Mon, 17 Sep 2018 05:11:39 +0000</pubDate>
      <link>https://dev.to/alakra/dropping-css-frameworks-for-grid-and-flexbox-543i</link>
      <guid>https://dev.to/alakra/dropping-css-frameworks-for-grid-and-flexbox-543i</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GX_aqQHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1504454449875-92cfa39e1315%3Fixlib%3Drb-0.3.5%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ%26s%3D6561d4b681332e316e7f21a6228ad9c8" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GX_aqQHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.unsplash.com/photo-1504454449875-92cfa39e1315%3Fixlib%3Drb-0.3.5%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ%26s%3D6561d4b681332e316e7f21a6228ad9c8" alt="Dropping CSS frameworks for Grid and Flexbox"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I was developing in a world full of CSS hacks going back from 2000 to 2010&lt;/strong&gt;. I was used to floating, inline-blocking and clearfixes to manage layout. I had tried to learn to use flexbox a few years ago, but it was when it was first introduced and most of the properties were browser-prefixed and didn't always work consistently. So I just gave up and put down front-end development down for a while I waited for things to mature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I avoided the pain by subscribing to the camps that used things like &lt;a href="http://getbootstrap.com/"&gt;Bootstrap&lt;/a&gt;, &lt;a href="https://foundation.zurb.com/"&gt;Foundation&lt;/a&gt; and &lt;a href="http://getskeleton.com/"&gt;Skeleton&lt;/a&gt;&lt;/strong&gt;. These were safe harbors where I could build applications quickly and focus on providing solid backends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My interest was sparked again when I walked over to my coworker and asked him what he was working on&lt;/strong&gt;. He showed me two tutorials of CSS &lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/"&gt;grid&lt;/a&gt; and &lt;a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/"&gt;flex&lt;/a&gt; and gave me a quick proof-of-concept of what they both could do together and I was blown away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I decided to build a page without a CSS framework only using grid and flexbox&lt;/strong&gt;. I have to say that I am very pleased with how straightforward and simple it was to make a functional layout without worrying too much about the structure of my HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a CSS grid and flexbox workflow for a fixed-width layout look like?
&lt;/h2&gt;

&lt;p&gt;Here's the &lt;code&gt;HTML&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;
    &amp;lt;meta name="description" content=""&amp;gt;
    &amp;lt;meta name="author" content=""&amp;gt;

    &amp;lt;title&amp;gt;Test Grid Layouts&amp;lt;/title&amp;gt;
    &amp;lt;link rel="stylesheet" href="styles.css"&amp;gt;
  &amp;lt;/head&amp;gt;

  &amp;lt;body&amp;gt;
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;header&amp;gt;
        &amp;lt;nav&amp;gt;
          &amp;lt;div id="logo"&amp;gt;Using Grid&amp;lt;/div&amp;gt;
          &amp;lt;ul&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;About&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Blog&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;a href="#"&amp;gt;Contact&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
          &amp;lt;/ul&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/header&amp;gt;

      &amp;lt;main&amp;gt;
        &amp;lt;div class="content"&amp;gt;
          &amp;lt;section class="hero"&amp;gt;
            &amp;lt;h3&amp;gt;Color Me Black&amp;lt;/h3&amp;gt;
          &amp;lt;/section&amp;gt;

          &amp;lt;article&amp;gt;
            &amp;lt;h1&amp;gt;Title&amp;lt;/h1&amp;gt;
            &amp;lt;p&amp;gt;I love content!&amp;lt;/p&amp;gt;
          &amp;lt;/article&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/main&amp;gt;

      &amp;lt;footer&amp;gt;
        &amp;lt;nav&amp;gt;
          &amp;lt;div class="siteinfo"&amp;gt;Made by Angelo&amp;lt;/div&amp;gt;
        &amp;lt;/nav&amp;gt;
      &amp;lt;/footer&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the &lt;code&gt;CSS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  font-family: 'Roboto', 'Helvetica', sans-serif;
}

.container {
  display: grid;                       
  min-height: 100%;                    
  grid-template-rows: 48px [stage] auto 48px;  
  grid-template-columns: 100%;
}

#logo {
  color: #FFFFFF;
  font-size: 1.5em;
}

header {
  display: grid;
  grid-template-columns: auto [head-center] 832px auto;
  height: 48px;
  background-color: #000000;
}

header &amp;gt; nav {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-start;
  align-items: center;
  grid-column-start: head-center;
  grid-column-end: span 1;
}

header &amp;gt; nav ul {
  margin: 0 0 0 auto;
}

header &amp;gt; nav ul li {
  display: inline;
  padding-left: 8px;
}

header &amp;gt; nav ul li a {
  color: #FFFFFF;
  text-decoration: none;
  text-transform: uppercase;
}

header &amp;gt; nav ul li a:hover {
  color: #AAAAAA;
}

main {
  display: grid;
  grid-template-columns: auto [main] 832px auto;
  grid-template-rows: auto;
  grid-row-start: stage;
  grid-row-end: span 1;
}

main &amp;gt; div.content {
  grid-column-start: main;
  grid-column-end: span 1;
}

main &amp;gt; div.content .hero {
  height: 300px;
  width: 100%;
  background-color: #000000;
  color: #FFFFFF;
}

main &amp;gt; div.content .hero h3 {
  padding: 16px;
}

footer {
  display: grid;
  grid-template-columns: auto [foot-center] 832px auto;
  grid-template-rows: 48px;
  background-color: #000000;
}

footer &amp;gt; nav {
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: flex-end;
  align-items: center;
  grid-column-start: foot-center;
  grid-column-end: span 1;
}

footer &amp;gt; nav &amp;gt; .siteinfo {
  color: #FFFFFF;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;I have some other nifty things in here to make things look pleasant, but we should really focus on where &lt;code&gt;display: grid&lt;/code&gt; and &lt;code&gt;display: flex&lt;/code&gt; is used&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;.container&lt;/code&gt; element is our top-level grid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.container {
  display: grid;                       
  min-height: 100%;                    
  grid-template-rows: 48px [stage] auto 48px;  
  grid-template-columns: 100%;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we use &lt;code&gt;grid-template-rows&lt;/code&gt; to define our top-level rows (from top to bottom). These can be a fixed size, a percentage or &lt;code&gt;auto&lt;/code&gt;. Each specification under the property is mapped to a child item in the order of definition. For example, the first &lt;code&gt;48px&lt;/code&gt; entry is my first row, &lt;code&gt;auto&lt;/code&gt; (which is aliased to &lt;code&gt;stage&lt;/code&gt;) is my second row, and &lt;code&gt;48px&lt;/code&gt; is my final and last row. I've also specified that I want the &lt;code&gt;grid-template-columns&lt;/code&gt; to expand the full width of my container.&lt;/p&gt;

&lt;p&gt;Now that I've done this, I have to think about the direct child elements that I create from that grid element because all the properties I applied are to the direct children of this parent element.&lt;/p&gt;

&lt;p&gt;My child elements (my grid items) from this parent of &lt;code&gt;.container&lt;/code&gt; are &lt;code&gt;header&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;footer&lt;/code&gt;. I define properties on these items to tell them where they should go on the grid.&lt;/p&gt;

&lt;p&gt;Let's take a look at &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;main {
  display: grid;
  grid-template-columns: auto [main] 832px auto;
  grid-template-rows: auto;
  grid-row-start: stage;
  grid-row-end: span 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm doing several things here. I'm defining another grid under the top-level &lt;code&gt;.container&lt;/code&gt; grid and I'm telling this grid item to start where the &lt;code&gt;stage&lt;/code&gt; row begins and then extend (or &lt;code&gt;span&lt;/code&gt;) 1 cell space down from it. If I had not aliased the starting row to &lt;code&gt;stage&lt;/code&gt;, then I would have to count the number of rows down I would want to start from and enter that number (in this case, it would have been &lt;code&gt;2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is basically all there is to it.&lt;/strong&gt; While this is not like the HTML &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; tag, it's mental model of placement is very similar. You can think of &lt;code&gt;colspan&lt;/code&gt; and &lt;code&gt;rowspan&lt;/code&gt; working very much like the &lt;code&gt;span&lt;/code&gt; property above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;To me, the two most important concepts to get are the parent element where the &lt;code&gt;grid&lt;/code&gt; layout is defined and the child elements where each "item" is defined&lt;/strong&gt;. An item is a DOM element that is mapped as content to a certain location in the grid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can nest &lt;code&gt;grid&lt;/code&gt; to get more complex layouts.&lt;/strong&gt; I did this so I could extend the backgrounds of my header and footer across the width of my page, but also maintain an "internal" grid on the &lt;code&gt;main&lt;/code&gt; element where content would be centered with margins that have an automatic width.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;While I used &lt;code&gt;grid&lt;/code&gt; to manage the layout, I used&lt;/strong&gt; &lt;code&gt;flex&lt;/code&gt; &lt;strong&gt;to manage the positioning behavior of child elements within the layout.&lt;/strong&gt; This is not just vertical and horizontal positioning, but relative spacing between children and even ordering. Flex is great at this sort of thing and can (and has) been used for layouts, but in the end, it starts to really feel hacky as your DOM gets more complex. So use &lt;code&gt;grid&lt;/code&gt; if you are trying to design big picture components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For&lt;/strong&gt; &lt;code&gt;grid&lt;/code&gt; &lt;strong&gt;, there are also more things to think about like lines, tracks, areas and cells. I've also made heavy use of aliases.&lt;/strong&gt; These are all things you should play with and understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So it's best to get experimenting.&lt;/strong&gt; Go ahead and copy the HTML directly to a file and save it as &lt;code&gt;index.html&lt;/code&gt; and then save the CSS as &lt;code&gt;styles.css&lt;/code&gt; and plop them in a folder.&lt;/p&gt;

&lt;p&gt;Assuming you have Python 3 installed and you have a unix shell available you can serve these up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd YOUR_FOLDER
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open up a browser to &lt;code&gt;http://localhost:8000&lt;/code&gt; and start adjusting CSS values using the built-in developer console in your browser or edit the files directly on disk and hit refresh on the browser for every change you want to make.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Also, try it with some of the mobile views. You'll quickly see the width is fixed. Can you make it work in a fluid or responsive way?&lt;/strong&gt; Here's a hint: Look at the HTML and CSS of &lt;a href="https://angelolakra.com"&gt;this blog site&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;There are lots of things you can do with grid.&lt;/strong&gt; You can throw in media queries and you can make your layouts completely fluid if you wish. Most modern browsers support grid and flex.  Take a look at &lt;a href="https://css-tricks.com/snippets/css/complete-guide-grid/"&gt;the grid guide&lt;/a&gt; and &lt;a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/"&gt;the flexbox guide&lt;/a&gt; or at &lt;a href="https://www.w3.org/TR/css-grid-1/"&gt;the spec itself&lt;/a&gt; to get more information and most importantly – throw away your hacks!&lt;/p&gt;




&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;CSS Grid Spec: &lt;a href="https://www.w3.org/TR/css-grid-1/#overview-placement"&gt;Placing Items&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;CSS 2 Spec: &lt;a href="https://www.w3.org/TR/CSS2/visudet.html#min-max-heights"&gt;Minimum and maximum heights: 'min-height' and 'max-height'&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>grid</category>
      <category>flexbox</category>
    </item>
    <item>
      <title>On Naming Contextual Modules and Functions in Elixir</title>
      <dc:creator>Angelo Lakra</dc:creator>
      <pubDate>Wed, 29 Aug 2018 19:15:40 +0000</pubDate>
      <link>https://dev.to/alakra/on-naming-contextual-modules-and-functions-in-elixir-1mi4</link>
      <guid>https://dev.to/alakra/on-naming-contextual-modules-and-functions-in-elixir-1mi4</guid>
      <description>

&lt;p&gt;There are some very simple rules I follow that make code easy to read, reason about and change as I write software. I like how the &lt;a href="https://phoenixframework.org/"&gt;Phoenix Framework&lt;/a&gt; encourages the use of &lt;a href="https://hexdocs.pm/phoenix/contexts.html#thinking-about-design"&gt;Contexts&lt;/a&gt; to describe how to organize code into specific modules and functions. I even like their naming conventions.&lt;/p&gt;

&lt;p&gt;I think these ideas can be used in any project that models logic that we encounter in the world. In fact, I used many of the ideas in &lt;a href="https://github.com/alakra/ticket-to-ride-core/"&gt;my Ticket to Ride implementation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;It's hard to make code (or APIs) easy to read in the very beginning&lt;/h2&gt;

&lt;p&gt;This is always a challenge for me when I don't know the full breadth of what I am building.  It's like writing a draft for a story or blog post. I  experiment with words and code organization and only after some time do things start to fall into the right places.&lt;/p&gt;

&lt;p&gt;In general, I try not to stress too much about it because I stick to a few tenets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;verb-noun&lt;/code&gt; style function names&lt;/li&gt;
&lt;li&gt;Don't use corporate sounding words to name your modules (like &lt;code&gt;manager&lt;/code&gt;, &lt;code&gt;strategy&lt;/code&gt;, &lt;code&gt;factory&lt;/code&gt;, etc.) unless they are explicitly described in your domain. &lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;typespecs&lt;/code&gt; for every public function (even if it is a resource under your domain)&lt;/li&gt;
&lt;li&gt;If a map is getting passed around, consider giving it a formal type as a &lt;code&gt;struct&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Alias any internal, dependent modules you use in a module.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Using verb-noun function names&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://github.com/alakra/ticket-to-ride-core"&gt;Ticket to Ride&lt;/a&gt;, I use the following verb prefixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add&lt;/li&gt;
&lt;li&gt;begin&lt;/li&gt;
&lt;li&gt;create&lt;/li&gt;
&lt;li&gt;deal&lt;/li&gt;
&lt;li&gt;destroy&lt;/li&gt;
&lt;li&gt;draw&lt;/li&gt;
&lt;li&gt;find&lt;/li&gt;
&lt;li&gt;get&lt;/li&gt;
&lt;li&gt;has&lt;/li&gt;
&lt;li&gt;join&lt;/li&gt;
&lt;li&gt;leave&lt;/li&gt;
&lt;li&gt;list&lt;/li&gt;
&lt;li&gt;login&lt;/li&gt;
&lt;li&gt;logout&lt;/li&gt;
&lt;li&gt;perform&lt;/li&gt;
&lt;li&gt;register&lt;/li&gt;
&lt;li&gt;remove&lt;/li&gt;
&lt;li&gt;replace&lt;/li&gt;
&lt;li&gt;reset&lt;/li&gt;
&lt;li&gt;return&lt;/li&gt;
&lt;li&gt;select&lt;/li&gt;
&lt;li&gt;setup&lt;/li&gt;
&lt;li&gt;shuffle&lt;/li&gt;
&lt;li&gt;start&lt;/li&gt;
&lt;li&gt;stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a lot of verbs, but they identify a specific action. That specificity helps me understand what a function is going to do. If I only had the noun as the function name, does it indicate to me what is going to happen or what side effects will take place? If I use a vague verb like &lt;code&gt;perform&lt;/code&gt;, should I consider renaming it to something else?&lt;/p&gt;

&lt;h2&gt;Naming modules that make sense for your problem domain&lt;/h2&gt;

&lt;p&gt;I stay away from corporate sounding module names like &lt;code&gt;strategy&lt;/code&gt;, &lt;code&gt;manager&lt;/code&gt;, etc. because I see them as misleading patterns that distract from a module's purpose.  The module name should indicate the domain or resource and nothing else. Let the function names define what its abilities and purposes are.&lt;/p&gt;

&lt;p&gt;I think &lt;a href="https://en.wikipedia.org/wiki/Paul_Graham_(programmer)"&gt;Paul Graham&lt;/a&gt; was onto something when he said this in &lt;a href="http://www.paulgraham.com/icad.html"&gt;Revenge of the Nerds&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough-- often that I'm generating by hand the expansions of some macro that I need to write.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Write typespecs&lt;/h2&gt;

&lt;p&gt;I see this language feature is as powerful as writing tests. Not because they &lt;em&gt;correct&lt;/em&gt; me when I do something wrong, but they &lt;em&gt;show&lt;/em&gt; me that I have gone onto a path of complexity that feels like it may cause me trouble later. For example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@spec claim_route(State.t, User.id, Route.t, TrainCard.t, cost()) ::
  {:ok, State.t} | {:error, :unavailable}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is from &lt;a href="https://github.com/alakra/ticket-to-ride-core/blob/eafb3c4d78b477c90baa80b3dd424a97f83ca315/lib/ttr_core/mechanics.ex#L189"&gt;TtrCore.Mechanics.claim_route/5&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I write a typespec that looks like this (more than 4 arguments with varying types), I start to feel uncomfortable and I try to find ways to simplify it.  &lt;/p&gt;

&lt;p&gt;What I do like about this is that it shows me exactly how varied my types are and I can reason about either removing them or combining them before writing any code. It's harder to do this without type information.&lt;/p&gt;

&lt;p&gt;In addition, I can also reason about my possible outputs. Currently, these look reasonable.&lt;/p&gt;

&lt;h2&gt;Assigning types to structured data and passing it around&lt;/h2&gt;

&lt;p&gt;After combining a bunch of types into some compound type (like a &lt;code&gt;map&lt;/code&gt; or &lt;code&gt;tuple&lt;/code&gt;), I will pass that around in my internal APIs to get work done.  &lt;/p&gt;

&lt;p&gt;If the amount of work being done with the that data has two or more domain-based operations, then I feel like my data should be formalized into some named type.&lt;/p&gt;

&lt;p&gt;Sometimes this data has to leave a domain and has to go into another one and I think that's OK as long as the operations in the foreign domain aren't trying to act directly on the data in a way that cause its meaning to change.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://hexdocs.pm/phoenix/contexts.html#returning-ecto-structures-from-context-apis"&gt;https://hexdocs.pm/phoenix/contexts.html#returning-ecto-structures-from-context-apis&lt;/a&gt; as one explanation for this type of reasoning.&lt;/p&gt;

&lt;p&gt;If it is needed to read that data in order to derive new data in a foreign domain, then that seems OK because that new data is relevant to that foreign domain and can be formalized as a type there.&lt;/p&gt;

&lt;p&gt;The place this becomes dangerous is when a type needs to get associated with "extra" data and the "extra" data is merged directly onto the compound data type across multiple domains and still gets called by the same named type.  &lt;/p&gt;

&lt;p&gt;This is wrong. It begets all kinds of misunderstanding of what is happening in the code. If there is a need to do this type of association, a new type needs to be created to encapsulate both of these pieces of information or the original type needs to be modified.&lt;/p&gt;

&lt;p&gt;I tend for the first option because it prevents a single type from become a "god" type that knows about too many things.&lt;/p&gt;

&lt;h2&gt;Alias internal modules in your modules&lt;/h2&gt;

&lt;p&gt;I like to know what my dependencies are in a module at the very beginning. Aliasing offers this as an excellent side-effect to shortening names used in module.  &lt;/p&gt;

&lt;p&gt;When I see lots of aliases in a particular module, can I assume that my module knows about too many things? Is it a sign that a new domain or resource should be created to handle a portion of these concerns?&lt;/p&gt;

&lt;h2&gt;Still no silver bullets&lt;/h2&gt;

&lt;p&gt;None of these tenets are silver bullets. They won't save me from poor performing code or convoluted logic that exists in the real world, but they do shield me from my own disorganization and give me enough principles to manage code bases over many years.&lt;/p&gt;


</description>
      <category>elixir</category>
      <category>tickettoride</category>
      <category>modules</category>
      <category>namingconventions</category>
    </item>
    <item>
      <title>Defining Routes and Tickets in Ticket to Ride with Elixir Macros</title>
      <dc:creator>Angelo Lakra</dc:creator>
      <pubDate>Thu, 23 Aug 2018 03:18:54 +0000</pubDate>
      <link>https://dev.to/alakra/defining-routes-and-tickets-in-ticket-to-ride-with-elixir-macros-2fhd</link>
      <guid>https://dev.to/alakra/defining-routes-and-tickets-in-ticket-to-ride-with-elixir-macros-2fhd</guid>
      <description>

&lt;p&gt;A while back I decided that using macros to define the routes and tickets for &lt;a href="https://github.com/alakra/ticket-to-ride-core"&gt;my implementation of ticket to ride in Elixir&lt;/a&gt; would be a good idea because of the data structure that I had envisioned at the time.&lt;/p&gt;

&lt;p&gt;The macro usage looks like this:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule TtrCore.Board.Routes do
  use TtrCore.Board.Router

  defroute Atlanta, to: Charleston, distance: 2
  defroute Atlanta, to: Miami, distance: 5, trains: [:passenger]
  defroute Atlanta, to: Raleigh, distance: 2, trains: [:any, :any]
  defroute Atlanta, to: Nashville, distance: 1
  defroute Atlanta, to: New.Orleans, distance: 4, trains: [:box, :tanker]
  defroute Boston, to: Montreal, distance: 2, trains: [:any, :any]
  defroute Boston, to: New.York, distance: 1, trains: [:coal, :box]

  # And more routes...
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I realized that my implementation was far too complex for the calculations needed of the game, so I scrapped the data structure for a much flatter and simpler one.&lt;/p&gt;

&lt;p&gt;Here's the original:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule TicketToRide.Router do
  alias TicketToRide.{NoOriginFoundError,
                      NoDestinationSpecifiedError,
                      NoDistanceSpecifiedError}

  defmodule Origin do
    defstruct [
      name: nil,
      destinations: %{}
    ]
  end

  defmodule Destination do
    defstruct [
      name: nil,
      distance: 0,
      trains: MapSet.new
    ]
  end

  defmacro __using__ (_opts) do
    quote do
      import unquote( __MODULE__ )
      Module.register_attribute __MODULE__ , :origins, accumulate: false, persist: false
      Module.put_attribute __MODULE__ , :origins, %{}
      @before_compile unquote( __MODULE__ )
    end
  end

  # API

  defmacro defroute(name, args \\ []) do
    quote do
      @origins Map.merge(@origins, update_origins(@origins, unquote(name), unquote(args)))
    end
  end

  defmacro __before_compile__ (_env) do
    quote do
      def all, do: @origins
      def get(name), do: Map.fetch(@origins, name)
    end
  end

  def update_origins(origins, name, args) do
    source = get(origins, name, autocreate: true)

    destination = get(origins, args[:to], autocreate: true)
    destination_options = [
      to: name,
      distance: args[:distance],
      trains: args[:trains]
    ]

    %{ name =&amp;gt; update(source, args),
       args[:to] =&amp;gt; update(destination, destination_options) }
  end

  # Private

  defp get(origins, name, opts \\ [autocreate: false]) do
    case Map.fetch(origins, name) do
      {:ok, origin} -&amp;gt; origin
      :error -&amp;gt; get_on_error(name, opts[:autocreate])
    end
  end

  defp get_on_error(name, autocreate) do
    if autocreate do
      %Origin{name: name}
    else
      raise NoOriginFoundError, name: name
    end
  end

  defp update(origin, args) do
    destination_name = extract_destination_name(origin, args)
    trains = extract_trains(args)

    destination = update_destination(origin, destination_name, trains, args)
    destinations = Map.put(origin.destinations, destination_name, destination)

    %{origin | destinations: destinations}
  end

  defp update_destination(origin, destination, trains, args) do
    case Map.fetch(origin.destinations, destination) do
      {:ok, dest} -&amp;gt;
        %{dest | trains: MapSet.union(dest.trains, trains)}
      :error -&amp;gt;
        distance = extract_distance(origin, args)
        %Destination{name: destination, distance: distance, trains: trains}
    end
  end

  defp extract_destination_name(origin, args) do
    case args[:to] do
      nil -&amp;gt; raise NoDestinationSpecifiedError, from: origin.name
      destination -&amp;gt; destination
    end
  end

  defp extract_distance(origin, args) do
    case args[:distance] do
      nil -&amp;gt; raise NoDistanceSpecifiedError, from: origin.name, to: args[:to]
      distance -&amp;gt; distance
    end
  end

  defp extract_trains(args) do
    case args[:trains] do
      nil -&amp;gt; MapSet.new([:any])
      trains -&amp;gt; MapSet.new(trains)
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the new:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;defmodule TtrCore.Board.Router do
  @moduledoc false

  alias TtrCore.Board.Route

  defmacro __using__ (_opts) do
    quote do
      import unquote( __MODULE__ )
      Module.register_attribute __MODULE__ , :routes, accumulate: true, persist: true
      @before_compile unquote( __MODULE__ )
    end
  end

  defmacro defroute(from, args \\ []) do
    to = args[:to]
    distance = args[:distance]
    trains = args[:trains] || [:any]

    quote do
      Enum.each(unquote(trains), fn train -&amp;gt;
        @routes {unquote(from), unquote(to), unquote(distance), train}
      end)
    end
  end

  defmacro __before_compile__ (_env) do
    quote do
      @spec get_routes() :: [Route.t]
      def get_routes, do: @routes

      @spec get_claimable_routes([Route.t]) :: [Route.t]
      def get_claimable_routes(claimed), do: @routes -- claimed
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The main changes were around the data structure to build up the module attribute &lt;code&gt;@routes&lt;/code&gt;. I was using a nested map within a list and now I am justing using a list of tuples.&lt;/p&gt;

&lt;p&gt;The reason I was trying to use a nested map was because I wanted to map every city to a list of possible destinations. This sounded like a good idea for figuring out which cities on the map are connected to another to calculate the final score, but turned out to be irrelevant for most of the game.&lt;/p&gt;

&lt;p&gt;There were also features for custom error checking at compile time. If I did not follow the format of the macro, the macro would throw me a relevant error message about what I did wrong. But since the data is simple, the compiler's AST checking was more than adequate to indicate where I went awry.&lt;/p&gt;

&lt;p&gt;I only needed to calculate the longest route and ticket points when I calculated the final score. In both the old and new implementation, a &lt;code&gt;map/reduce&lt;/code&gt; would be needed to calculate which player got the longest route. I reasoned that less data complexity would lead to less algorithmic complexity.&lt;/p&gt;

&lt;p&gt;And that's why I changed it.&lt;/p&gt;


</description>
      <category>elixir</category>
      <category>macros</category>
      <category>tickettoride</category>
    </item>
  </channel>
</rss>
