<?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: Carsten Zimmermann</title>
    <description>The latest articles on DEV Community by Carsten Zimmermann (@carpmeister).</description>
    <link>https://dev.to/carpmeister</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%2F572614%2Fa49091bb-72dd-4f7d-89eb-d9b2f537d042.png</url>
      <title>DEV Community: Carsten Zimmermann</title>
      <link>https://dev.to/carpmeister</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/carpmeister"/>
    <language>en</language>
    <item>
      <title>Don't call it `*_id`!</title>
      <dc:creator>Carsten Zimmermann</dc:creator>
      <pubDate>Sun, 07 May 2023 10:08:22 +0000</pubDate>
      <link>https://dev.to/marleyspoon/dont-call-it-id-5fbf</link>
      <guid>https://dev.to/marleyspoon/dont-call-it-id-5fbf</guid>
      <description>&lt;p&gt;In a distributed system, we often need to store data that we do not own. We might use it as a unique identifier across domains or the system we &lt;em&gt;do&lt;/em&gt; own needs to proxy it to yet another service.&lt;/p&gt;

&lt;p&gt;In many cases, the origin system exposes it in the same way it is represented internally, for instance: a foreign key name of a relational database:&lt;/p&gt;
Fig. 1: local relational table, rev. 1


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+----+--------------+----------------------+
| id | name         | backend              |
+----+--------------+----------------------+
| 42 | Marley Spoon | elixir, ruby, python |
+----+--------------+----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Translated to JSON, we could send it over the wire as follows:&lt;/p&gt;
Fig. 2: example JSON payload


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marley Spoon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"backend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"elixir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ruby"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;A service consuming the information may want to add prefixes to scope it for "companies" and store/cache it like so:&lt;/p&gt;
Fig. 3: local relational table, rev. 2


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------+--------------+----------------------+
| company_id | company_name | backend              |
+------------+--------------+----------------------+
| 42         | Marley Spoon | elixir, ruby, python |
+------------+--------------+----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;But here's the problem: as engineers, we look at &lt;code&gt;_id&lt;/code&gt; fields and immediately think of it as &lt;strong&gt;integers&lt;/strong&gt;. However, the consuming service has no control over the data it receives and the data type is only &lt;em&gt;assumed&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you use that distributed ID field as a local foreign key: some external system controls the value and an unforeseen change might break our setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identification
&lt;/h2&gt;

&lt;p&gt;It has proven valuable to us to use the pattern &lt;code&gt;*_identifier&lt;/code&gt; to indicate that…&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it &lt;em&gt;is&lt;/em&gt; some kind of a unique identifier&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;some other&lt;/em&gt; system has control over it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the &lt;code&gt;*_identifier&lt;/code&gt; value is to be stored, it should always be &lt;em&gt;saved as a string type&lt;/em&gt;. Almost anything can be coerced into a string, and that way we guarantee that the origin system can choose whatever they want for their unique identifier.&lt;/p&gt;

&lt;p&gt;This is particularly true if the origin system decided to move to using &lt;strong&gt;UUIDs&lt;/strong&gt;. A final version of the local relational table above could look like this:&lt;/p&gt;
Fig. 4: local relational table, rev. 4


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------------------------------+--------------+----
| company_identifier                   | company_name | …
+--------------------------------------+--------------+----
| 328129ae-df4e-4168-94d3-2572b4b343ef | Marley Spoon | …
+--------------------------------------+--------------+----
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Payload
&lt;/h2&gt;

&lt;p&gt;If the system &lt;em&gt;exposing&lt;/em&gt; the data is controlled by your organisation, we can support this at the source.&lt;/p&gt;

&lt;p&gt;It is a common pitfall of API designs, especially RESTful APIs, to expose a resource exactly like you represent it in your database. This makes sense to reduce the cognitive load of the team maintaining the API. However, the data layer will inevitably change, rendering this point moot: the DB representation has to be translated to maintain a stable contract. Why not abstract from the data layer to begin with and name the keys in the payload in a system-agnostic way?&lt;/p&gt;
Fig. 5: JSON payload abstracted from persistence


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"company_identifier"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"328129ae-df4e-4168-94d3-2572b4b343ef"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"company_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Marley Spoon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"backend"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"elixir"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ruby"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;*_identifier&lt;/code&gt; instead of &lt;code&gt;*_id&lt;/code&gt; fields for externally owned data&lt;/li&gt;
&lt;li&gt;Prefer a string type over integer for &lt;code&gt;*_identifier&lt;/code&gt; values&lt;/li&gt;
&lt;li&gt;Avoid a 1:1-map of your persistence model to your external API &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>backend</category>
      <category>api</category>
      <category>shorts</category>
    </item>
    <item>
      <title>Constant Doubts</title>
      <dc:creator>Carsten Zimmermann</dc:creator>
      <pubDate>Thu, 23 Mar 2023 12:58:47 +0000</pubDate>
      <link>https://dev.to/marleyspoon/constant-doubts-2gbm</link>
      <guid>https://dev.to/marleyspoon/constant-doubts-2gbm</guid>
      <description>&lt;p&gt;I always had mixed feelings towards Ruby constants. First, &lt;strong&gt;they're not that constant&lt;/strong&gt; to begin with. You can reassign a constant at runtime freely and all you get is a warning:&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="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:lol&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;warning: &lt;/span&gt;&lt;span class="n"&gt;already&lt;/span&gt; &lt;span class="n"&gt;initialized&lt;/span&gt; &lt;span class="n"&gt;constant&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;warning: &lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Contrary to popular belief, a &lt;code&gt;#freeze&lt;/code&gt; won't help, either. Yes, it makes the &lt;em&gt;object&lt;/em&gt; you're assigning immutable, but it doesn't prevent another constant &lt;em&gt;assignment&lt;/em&gt;:&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="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;001&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;002&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"baz"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;warning: &lt;/span&gt;&lt;span class="n"&gt;already&lt;/span&gt; &lt;span class="n"&gt;initialized&lt;/span&gt; &lt;span class="n"&gt;constant&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="ss"&gt;warning: &lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="n"&gt;definition&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;here&lt;/span&gt;
&lt;span class="n"&gt;irb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="mo"&gt;003&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# 🤷&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;small&gt;(It would be nice to be able to change warning into an error, but there's certainly no &lt;code&gt;RUBYOPT&lt;/code&gt; flag that I know of.)&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;But most importantly: unless they're defined in the top level object space, &lt;strong&gt;I consider them implementation details&lt;/strong&gt;. If an instance of &lt;code&gt;A::Nested::Class&lt;/code&gt; accesses  &lt;code&gt;Some::Other::CONST&lt;/code&gt;, it crosses 5-6 boundaries (depending on where you start counting). That's not actually respecting that module's privacy and also a violation of the &lt;a href="https://en.wikipedia.org/wiki/Law_of_Demeter" rel="noopener noreferrer"&gt;Law of Demeter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;private_constant&lt;/code&gt; all the things!
&lt;/h2&gt;

&lt;p&gt;By default, constants are public. Most software engineers are very eager to work with the &lt;code&gt;private&lt;/code&gt; keyword to limit the public API of their instances, but it's rarer to see that same rigor applied to class or module-level constants.&lt;/p&gt;

&lt;p&gt;Ruby has &lt;code&gt;private_constant&lt;/code&gt; since basically forever (&lt;small&gt;MRI v1.9.3 to be precise&lt;/small&gt;). It accepts one or more symbols referring to defined constants in its scope:&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;module&lt;/span&gt; &lt;span class="nn"&gt;MyModule&lt;/span&gt;
  &lt;span class="no"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;freeze&lt;/span&gt;
  &lt;span class="no"&gt;LOL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:wat?&lt;/span&gt;

  &lt;span class="n"&gt;private_constant&lt;/span&gt; &lt;span class="ss"&gt;:FOO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:LOL&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;
    &lt;span class="no"&gt;FOO&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;Any attempt to access &lt;code&gt;MyModule::FOO&lt;/code&gt; from outside &lt;code&gt;MyModule&lt;/code&gt; will raise a &lt;code&gt;NameError&lt;/code&gt; ("private constant MyModule::FOO referenced").&lt;/p&gt;

&lt;p&gt;Please note that &lt;code&gt;MyModule.foo&lt;/code&gt; still works (and returns the frozen string &lt;code&gt;"bar"&lt;/code&gt;) as it only accesses the private constant from within its defining scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Singleton) Methods Over Constants
&lt;/h2&gt;

&lt;p&gt;I mentioned I consider constants implementation details. A named identifier for a magic value, maybe something configurable and set at load time. And sometimes, you want to expose that to other components in your applications.&lt;/p&gt;

&lt;p&gt;As shown in the code snippet above, you can always create a singleton method / module function that wraps around a private constant.&lt;/p&gt;

&lt;p&gt;In my opinion, methods are in all cases superior to &lt;code&gt;CONSTANTS&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;you can defer (lazy load) the assignment&lt;/li&gt;
&lt;li&gt;you can memoize (&lt;code&gt;@class_var ||= ...&lt;/code&gt;) what's being assigned&lt;/li&gt;
&lt;li&gt;you can delegate the method call&lt;/li&gt;
&lt;li&gt;it's easier to stub a method than a constant in your tests&lt;/li&gt;
&lt;li&gt;it pairs well with making class/module-level value configurable on the application level, e.g. using a well-known &lt;code&gt;MyModule.configure(&amp;amp;block)&lt;/code&gt; format or by using &lt;a href="https://dry-rb.org/gems/dry-configurable/0.16/" rel="noopener noreferrer"&gt;dry-config&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;it feels much more OOP to send a message to an object than working with its constants (&lt;small&gt;also, I always feel that CONSTANTS YELL AT ME in the source code&lt;/small&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Points 1..5 all give you a great forward compatible way to refactor how your magic value is used, all for the small price of making your constants private and adding a getter singleton method around it if you really need to expose it to the outside world right away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforce Explicit Constant Visibility
&lt;/h2&gt;

&lt;p&gt;Unfortunately, there is no way to make all constant private by default, but RuboCop includes a &lt;a href="https://docs.rubocop.org/rubocop/1.46/cops_style.html#styleconstantvisibility" rel="noopener noreferrer"&gt;&lt;code&gt;RuboCop::Cop::Style::ConstantVisibility&lt;/code&gt;&lt;/a&gt; cop to at least make the constant scope explicit.&lt;/p&gt;

&lt;p&gt;I like that it makes you stop and think about what you're doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Named Classes Are Constants
&lt;/h2&gt;

&lt;p&gt;Now, constants aren't only referred to by &lt;code&gt;UPPERCASE&lt;/code&gt; identifiers: all class and module names are in fact constants, so you could argue that my criticism about accessing &lt;code&gt;Some::CONSTANT&lt;/code&gt; directly must also extend to a form like &lt;code&gt;Nested::Class.new&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And indeed it does, but that will be the topic of the next article. 😀&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Cover image credit: DALL·E 2.&lt;/small&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>opinion</category>
    </item>
    <item>
      <title>What's the point? The 3 Es.</title>
      <dc:creator>Carsten Zimmermann</dc:creator>
      <pubDate>Tue, 05 Apr 2022 12:00:54 +0000</pubDate>
      <link>https://dev.to/marleyspoon/whats-the-point-the-3-es-1804</link>
      <guid>https://dev.to/marleyspoon/whats-the-point-the-3-es-1804</guid>
      <description>&lt;p&gt;&lt;strong&gt;Musings on the arbitrary number we attach to tasks &amp;amp; stories&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once per moon, we find ourselves discussing both what dimensions we should consider when we’re doing our Backlog Refinement and what types of work should receive Story Points to begin with. Occasionally, the term →“Business Value” is tossed into the conversation, but for my heavily backend-focussed team, it is very difficult to attach that particular metric to a highly technical task – and we currently have a lot of them.&lt;/p&gt;

&lt;p&gt;This article originally aimed to conclude that conversation, a publicised Working Agreement if you will. It may serve as inspiration to others who wish to look at their pointing strategy through the lens of a Backend team. But as with most things on the internet, YMMV.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issue Types
&lt;/h2&gt;

&lt;p&gt;We work with Product Backlog Items (PBI) that can be categorised as one of the following:&lt;/p&gt;

&lt;h3&gt;
  
  
  Story
&lt;/h3&gt;

&lt;p&gt;Captures &lt;strong&gt;work from an end user’s perspective&lt;/strong&gt;, with varying definitions of what an end user is (for us, it can be another system consuming our public API). They typically follow the format of “&lt;em&gt;As &amp;lt;who&amp;gt; &amp;lt;when&amp;gt; &amp;lt;where&amp;gt;, I want &amp;lt;what&amp;gt; because &amp;lt;why&amp;gt;&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;Stories are pointed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;Describes an often &lt;strong&gt;technical aspect of an overarching goal&lt;/strong&gt;. This could be a necessary refactoring, foundational work, paying back technical debt, or general housekeeping chores.&lt;/p&gt;

&lt;p&gt;We point Tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug
&lt;/h3&gt;

&lt;p&gt;Represents a defect, something that isn’t working as intended. Bugs have varying priorities: some have a very low impact with known workarounds, the more urgent ones affect production and need to be addressed right away.&lt;/p&gt;

&lt;p&gt;Some Bugs we point, some Bugs we don’t:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-priority bugs that need to be added to current Sprint probably represent rework – a missed edge-case or something that slipped through QA. As such, it should not count towards the team’s →Velocity as that work should have gone into previous Sprints… so to speak&lt;/li&gt;
&lt;li&gt;Bugs for which we have workarounds or whose impact is considered low should be part of the normal prioritisation process. Attaching a number to it will help weighing against other items in the Backlog.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Spike
&lt;/h3&gt;

&lt;p&gt;Work to explore a new technology, test new processes, eliminate unknowns (see below, →Entropy). The goal is not to ship production-ready code, but rather to provide a proof of concept. Code produced while working on a Spike might deliberately forgo tests or sad path handling.&lt;/p&gt;

&lt;p&gt;The main &lt;strong&gt;output of a Spike is information&lt;/strong&gt;. The information is shared with the team. We currently do not point Spikes, but we time-box them (~2 days).&lt;/p&gt;

&lt;h3&gt;
  
  
  Epic
&lt;/h3&gt;

&lt;p&gt;A container for related issues of various types. Ideally, they have a defined end-date and all its member issues (Stories &amp;amp; Tasks, mainly) are defined &amp;amp; scoped together to avoid too much context switching.&lt;/p&gt;

&lt;p&gt;Possible anti-pattern: using an Epic to group related tickets in such a way that the Epic grows and grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interpreting Points: The Three Es (3Es)
&lt;/h2&gt;

&lt;p&gt;I understand story points to be one of the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Entanglement (as in: how many connections / interactions / dependencies)&lt;/li&gt;
&lt;li&gt;Effort (as in: how time consuming is the actual work)&lt;/li&gt;
&lt;li&gt;Entropy (as in: state of disorder, The Unknown)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Entanglement
&lt;/h3&gt;

&lt;p&gt;Entanglement reflects how many moving parts have to be considered, the literal complexity of the feature. Higher complexity will translate to more diligence considering side-effects or edge-cases, as well as requiring a more thorough QA process. &lt;/p&gt;

&lt;h3&gt;
  
  
  Effort
&lt;/h3&gt;

&lt;p&gt;Effort can be a measurement for how laborious a task is, even if it’s not rocket science. An example would be restructuring a code base where the goal is clear, but it will involve renaming many files and module names.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entropy
&lt;/h3&gt;

&lt;p&gt;Entropy expresses the uncertainty around a given task. It can cover blind-spots about the implications of a change, lack of experience with the domain or technology, a placeholder for the unknown Unknowns that might be uncovered while working on the task.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: if there’s too much entropy, creating a →Spike first is advisable.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Value
&lt;/h2&gt;

&lt;p&gt;Now, the Three Es don’t include the hallowed Business Value. After all, everything in agile software development is about continuously delivering value, right?&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no objective scale by which we can measure Business Value. For some cases, “revenue added / cost saved” would be a good unit of measure, but “customer satisfaction” is nigh impossible to translate to money, whereas “better fault tolerance” requires a lot of effort (and guesswork) to put a € sign next to it.&lt;/p&gt;

&lt;p&gt;Business Value is also time-dependent: it exists within the context of the organisation’s current situation and direction. Whatever arbitrary value we assign as Business Value for a story today might receive a completely different rating next month when re-evaluated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business Value is not a metric to feed into a team’s Velocity. It’s a means to prioritise work!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;Further reading: &lt;a href="https://medium.com/serious-scrum/business-value-9607a9ec02db"&gt;Business Value&lt;/a&gt; by Erik de Bos.&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Velocity &amp;amp; Capacity
&lt;/h2&gt;

&lt;p&gt;In Agile software development processes, the Sprint Velocity is a metric for the output of a team, measured in Story Points completed. Cynically, one could argue that it’s also a metric on how good the team is at estimating, but let’s assume that outliers in estimation are inevitable and are evened out over time.&lt;/p&gt;

&lt;p&gt;A (somewhat) deterministic pointing system where units of work (represented in PBIs) can be compared is key to assess the output of a team. Hopefully, the 3Es above help with that.&lt;/p&gt;

&lt;p&gt;&lt;span id="velocity"&gt;&lt;/span&gt;&lt;br&gt;
Now, &lt;strong&gt;Velocity&lt;/strong&gt; as a metric for a team’s output (i.e. the sum of completed story points) is meaningless if it’s not correlated to the input of the Sprint: the person-days that were available. It’s the Story Points / Available Capacity that really matters. The rationale being: one Sprint might have lower output because ⅓ of the team was recharging their batteries on well-deserved PTO (reduced input).&lt;/p&gt;

&lt;p&gt;If you want to track the relative efficiency of your Sprint, the relation of completed Story Points to Days Available provides the best insight and it also leads to more precise capacity planning: by calculating, say, a 4-Sprint-average of that ratio, you’ll end up with a multiplier to give you a good idea about how many Story Points you might complete in the next Sprint.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Sprint&lt;/th&gt;
&lt;th&gt;1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;th&gt;4&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A: Points completed&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B: Available Days&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Capacity Modified (A/B)&lt;/td&gt;
&lt;td&gt;0.5&lt;/td&gt;
&lt;td&gt;0.63&lt;/td&gt;
&lt;td&gt;0.67&lt;/td&gt;
&lt;td&gt;0.82&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 4-Sprint-average is (0.5 + 0.63 + 0.67 + 0.82) / 4 = 0.655. If you have 36 person-days available in your upcoming Sprint, you should aim for ~24 Story Points.&lt;/p&gt;

&lt;p&gt;It’s controversial if you want to count unfinished business towards your delivered output. I get why you wouldn’t want that – a User Story that isn’t fully done doesn’t provide value – but we also established that we won’t look at value.&lt;/p&gt;

&lt;p&gt;Being able to accurately plan what can be delivered in a Sprint is much more tangible than the incorporeal value and to that end, we split issues based on what was completed and what will roll over to the next Sprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In general, we already have a good grasp on how how many points to attach to a PBI – being primarily an &lt;a href="https://dev.to/t/elixir"&gt;#Elixir&lt;/a&gt; team, we have mentally assigned  &lt;code&gt;@default_points&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt; and just use the &lt;del&gt;module&lt;/del&gt; brain attribute in Scrum Poker. This is a good sign, as we're apparently doing ok at splitting work into bite-sized chunks already. But for more complex issues and when the estimates given differ a lot, it's good to do a sanity check by looking at the three dimensions  Entanglement, Effort, and Entropy separately.&lt;/p&gt;

&lt;p&gt;Additionally, finally having resolved that considering Business Value as something that should go into a PBI's story point estimation was a huge win.&lt;/p&gt;




&lt;p&gt;&lt;small&gt;Header photo credit: &lt;a href="https://pxhere.com/en/photo/1188433"&gt;PxHere&lt;/a&gt;, CC0 Public Domain&lt;/small&gt;&lt;/p&gt;

</description>
      <category>scrum</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
