<?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: RyTheTurtle</title>
    <description>The latest articles on DEV Community by RyTheTurtle (@rytheturtle).</description>
    <link>https://dev.to/rytheturtle</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%2F1269712%2F32818ef9-c079-4617-8810-a38c3f56e736.png</url>
      <title>DEV Community: RyTheTurtle</title>
      <link>https://dev.to/rytheturtle</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rytheturtle"/>
    <language>en</language>
    <item>
      <title>Scaling App Data in DynamoDB With Vertical Partitioning</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Tue, 26 Mar 2024 22:57:39 +0000</pubDate>
      <link>https://dev.to/rytheturtle/scaling-app-data-in-dynamodb-with-vertical-partitioning-5197</link>
      <guid>https://dev.to/rytheturtle/scaling-app-data-in-dynamodb-with-vertical-partitioning-5197</guid>
      <description>&lt;p&gt;Partitioning means to divide something up in to smaller, organized parts. When discussing application data, partitioning is used to increase the scalability of data storage solutions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Horizontal and Vertical Partitioning
&lt;/h2&gt;

&lt;p&gt;Typically, partitioning data is discussed in terms of vertical partitioning and horizontal partitioning. Consider a data model for a blog site that has the following structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;threads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How to Build Software&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A transistor is like a light switch...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;technology&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comments&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;timestamp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1234567890&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rytheturtle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Good read....&lt;/span&gt;&lt;span class="dl"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If our site has many threads, we'll need to figure out how to partition this data so we can scale out our database. &lt;/p&gt;

&lt;p&gt;To Horizontally partition our &lt;code&gt;threads&lt;/code&gt; table, we would take entire thread records and use some algorithm to divide up the records in the table across some number of partitions. If we have 3 different servers that store threads, each whole thread record is stored on one of the three servers using some algorithm to determine what server a particular thread is stored on. &lt;/p&gt;

&lt;p&gt;Vertical Partitioning still has the goal of splitting up data in to smaller parts, but does so by dividing up data by the columns rather than the rows. Take our above &lt;code&gt;threads&lt;/code&gt; example. Instead of dividing up whole users across our 3 different servers, the data is divided up amongst the different servers at the column/attribute level. So a single thread might have it's &lt;code&gt;title&lt;/code&gt; attribute stored on one server, and the same thread's &lt;code&gt;text&lt;/code&gt; attribute might live on a different server. &lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Partitioning Data and DynamoDB
&lt;/h2&gt;

&lt;p&gt;Vertical partitioning is a particularly useful concept when modeling application data in DynamoDB. DynamoDB is a fully managed, serverless, key/value, NoSQL database offering from AWS. Behind the scenes, DynamoDB(DDB) automatically distributes your application data using the &lt;strong&gt;Partition Key&lt;/strong&gt; attribute specified when creating a DDB table. &lt;/p&gt;

&lt;p&gt;While DDB is nearly infinitely scalable to reliably handle any amount of traffic at high scale and with consistent performance, there are some limitations that application developers have to keep in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;DDB is billed on Write Capacity Units (WCU) and Read Capacity Units (RCUs). WCUs and RCUs are billed in 1KB and 4KB size increments respectively, per second. DDB rounds up to the nearest 1KB/4KB respectively. &lt;/li&gt;
&lt;li&gt;Attribute sizes are effectively unlimited, Table sizes are effectively unlimited, but the size of a single item in a table is limited to no bigger than 400KB. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The implications of these limitations boil down to "big items are expensive to read and write, and your items have a size limit". &lt;/p&gt;

&lt;p&gt;Vertically partitioning your items in DDB unlocks several important benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Size of Data&lt;/strong&gt; vertically partitioning data means you can store virtually infinite sized data in DDB despite the 400KB limit. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read and Write costs&lt;/strong&gt; The application and load only relevant parts of an item for a specific feature, reducing the total read and write costs by not reading and writing unnecessary data. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, consider the discussion forum data model from earlier. If we just store the threads in a table as a single item with a partition key of "title" and the value includes everything in the JSON structure, we'll very quickly run in to problems. The Item will grow in size as more comments are added, making reading and writing each post to the database more expensive. Worse, our application will be forced to put hard limits on the number of comments that can be added to a post and the maximum size of a thread's text to ensure it can all fit in a single record. &lt;/p&gt;

&lt;p&gt;Both of these issues can be avoided by vertically partitioning the data. &lt;/p&gt;

&lt;h2&gt;
  
  
  Vertical Partitioning for DDB using Partition and Sort keys
&lt;/h2&gt;

&lt;p&gt;DynamoDB uniquely defines items in a table using a Partition Key and an optional Sort Key. The Partition Key (pk) is the main input to determine where an item will be stored. The Sort Key(sk), if defined, is used to sort the items inside of DDB's storage. Together, the PK and SK make up the unique identifier for a record. &lt;/p&gt;

&lt;p&gt;To vertically partition data in DynamoDB, it's best to use a combination of partition key and sort key. Define a partition key that keeps related data colocated, and use the sort key to separate out specific attributes from a logical entity in to separate DynamoDB items. &lt;/p&gt;

&lt;p&gt;Taking our blog site data from earlier, we can split the data for a single post in to several DDB items in the same table in the following way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// :: separates partition key from sort key,&lt;/span&gt;
  &lt;span class="c1"&gt;// for display purposes only&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009::META&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;META&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;thread_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How to Build Software&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;technology&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;createdAt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;98765432&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009::TEXT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TEXT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A transistor is like a light switch...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009::COMMENT#1234567890&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0000000009&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;COMMENT#1234567890&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;userId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rytheturtle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Good read....&lt;/span&gt;&lt;span class="dl"&gt;"&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;p&gt;Here, we've used a special naming scheme to partition our thread information in to different records for metadata, text, and comments. With this vertical partitioning, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Despite the 400KB/item limit of DDB, we can add an infinite amount of comments to a single &lt;code&gt;thread&lt;/code&gt; and simply load them by querying for keys with the prefix &lt;code&gt;&amp;lt;thread id&amp;gt;#COMMENT&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Adding a new comment involves only the WCUs to insert a new record with the content of that one comment, rather than writing to the entire list of comments for the thread. &lt;/li&gt;
&lt;li&gt;The size limits of a comment, metadata, and post are now independent of each other. The size of what is logically considered a single &lt;code&gt;thread&lt;/code&gt; can effectively grow infinitely as long as the individual pieces that we divided out with vertical partitioning adhere to the record size limits in DDB. &lt;/li&gt;
&lt;li&gt;Using thread ID as a partition key, we can still keep all the related data for a &lt;code&gt;thread&lt;/code&gt; co-located, making it more efficient to load multiple aspects of a specific &lt;code&gt;thread&lt;/code&gt; in a single batch read call if necessary. &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>database</category>
      <category>programming</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>QuickBytes: Stop Using Lombok's @NonNull</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sun, 24 Mar 2024 16:33:01 +0000</pubDate>
      <link>https://dev.to/rytheturtle/quickbytes-stop-using-lomboks-nonnull-26j</link>
      <guid>https://dev.to/rytheturtle/quickbytes-stop-using-lomboks-nonnull-26j</guid>
      <description>&lt;p&gt;Lombok is a powerful, if controversial, library that adds brevity and expressiveness to Java through it's annotation processing. One of the most popular annotations I see used in projects leveraging Lombok is the &lt;code&gt;@NonNull&lt;/code&gt; annotation. This annotation is commonly used to indicate that a field or method parameter is not supposed to be null.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@NonNull&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; 
    &lt;span class="c1"&gt;// bar will not be null here&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with this is communication. Many times I see developers using this on their methods and classes as a standard procedure for anything that's expected to not be &lt;code&gt;null&lt;/code&gt;. Upon further inspection, the reason often boils down to "if this field is null it will cause an exception, so I put &lt;code&gt;@NonNull&lt;/code&gt; here to make sure it's not null". &lt;/p&gt;

&lt;p&gt;The problem is that, per the Lombok documentation, &lt;code&gt;@NonNull&lt;/code&gt; simply generates a &lt;code&gt;null&lt;/code&gt; check condition at the top of your method and throws a &lt;code&gt;NullPointerException&lt;/code&gt; if the value is &lt;code&gt;null&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This is rarely the intended or desired behavior for a method. Instead, prefer a more thoughtful approach to handling input validation &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you can gracefully handle a &lt;code&gt;null&lt;/code&gt; input by selecting a default value or taking an alternative path of logic, write your own code to handle it gracefully instead of throwing an exception&lt;/li&gt;
&lt;li&gt;If you cannot handle a &lt;code&gt;null&lt;/code&gt; field gracefully, throw a specific exception that explains why a value is required in the exception message. &lt;code&gt;emailAddress is required for customer validation, and cannot be null&lt;/code&gt; is a more meaningful error message than &lt;code&gt;NullPointerException: field emailAddress is null&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;If you really just want to immediately short circuit your method if a &lt;code&gt;null&lt;/code&gt; value is present and don't have a more meaningful message to convey or an alternative path to take, use &lt;code&gt;@NonNull&lt;/code&gt; to autogenerate the null checks for you. &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>webdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>QuickBytes: Writing Concise, Extensible Methods</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Fri, 22 Mar 2024 17:05:06 +0000</pubDate>
      <link>https://dev.to/rytheturtle/quickbytes-writing-concise-extensible-methods-4ii3</link>
      <guid>https://dev.to/rytheturtle/quickbytes-writing-concise-extensible-methods-4ii3</guid>
      <description>&lt;p&gt;Creating short, extensible method signatures is a great way to build maintainable, readable code. Having too many parameters to a method is a common mistake people make when defining method signatures that hurts readability and extensibility. &lt;/p&gt;

&lt;p&gt;Consider the following method for transferring money between accounts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bank&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                   &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                   &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                   &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                   &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;the method has five input parameters, which makes each invocation difficult to read and easy to exceed line lengths &lt;/li&gt;
&lt;li&gt;it's easy to mix up the consecutive parameters of the same type. Looking at
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMillis&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; 
              &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"50.00"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
              &lt;span class="s"&gt;"XXX"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"YYY"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which of the parameters is &lt;code&gt;fromAccount&lt;/code&gt; and which one is &lt;code&gt;toAccount&lt;/code&gt;? &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extending this method is difficult. Let's say we need to send an email notification upon successful transfer of the money. With this current interface, we can

&lt;ol&gt;
&lt;li&gt;add another string parameter &lt;code&gt;emailAddress&lt;/code&gt;, but then we will be forced to update every place our &lt;code&gt;transferMoney&lt;/code&gt; function is called to include the new parameter. This is a breaking API change that forces callers to pass an extra parameter. The best case is that this interface is only used in our own code and we just have to go update every invocation of &lt;code&gt;transferMoney&lt;/code&gt; in our own code. If this is code consumed by external callers, we have bigger problems. &lt;/li&gt;
&lt;li&gt;add a new method for transferring money that has an extra parameter for &lt;code&gt;emailAddress&lt;/code&gt;. Not a big deal, but the more we add additional parameters or functionality, the more the interface is polluted with many variations of essentially the same operation.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can improve this by bundling up the parameters in to an object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bank&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This improved method signature is easier to read and extend. Combined with a builder pattern, parameters are easily understood and labeled even when we have many parameters of similar types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="n"&gt;transferDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nc"&gt;TransferDetails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"XXX"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YYY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMilis&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"50.00"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transferDetails&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, adding a new parameter to the method does not require breaking changes or overloading our method signature. We can simply add the new field to the input object and callers are free to add or ignore the new field without breaking existing invocations of the &lt;code&gt;transferMoney&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;emailAddress&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Bank&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="c1"&gt;// our previous invocation still works &lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="n"&gt;transferDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nc"&gt;TransferDetails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"XXX"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YYY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMilis&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"50.00"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transferDetails&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// but we can also start sending in email address &lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TransferDetails&lt;/span&gt; &lt;span class="n"&gt;transferDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nc"&gt;TransferDetails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"XXX"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toAccount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"YYY"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentTimeMilis&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"50.00"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;emailAddress&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someone@gmail.com"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;bank&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transferMoney&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transferDetails&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use parameter objects as a simple way to make your methods easier to read and extend. Happy coding :) &lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>java</category>
    </item>
    <item>
      <title>Simple, Effective Writing Tips for Software Developers</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sun, 03 Mar 2024 18:31:44 +0000</pubDate>
      <link>https://dev.to/rytheturtle/simple-effective-writing-tips-for-software-developers-38k0</link>
      <guid>https://dev.to/rytheturtle/simple-effective-writing-tips-for-software-developers-38k0</guid>
      <description>&lt;p&gt;Creating and maintaining effective documentation is expensive, and often under-prioritized when a team has a deep backlog of work. However, well written documentation is an invaluable mechanism for knowledge sharing and communication. Well-executed documentation effectively shares important knowledge across a team, improves productivity and breaks down &lt;a href="https://en.wikipedia.org/wiki/Information_silo"&gt;information silos&lt;/a&gt;. Below are 5 lightweight, effective forms of documentation that help capture important knowledge across a team's software development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. README.md
&lt;/h2&gt;

&lt;p&gt;Including a &lt;code&gt;README.md&lt;/code&gt; file directly with the source code is an easy way to document basic information about how to work with software. Typical content for a good &lt;code&gt;README.md&lt;/code&gt; includes basic information about the purpose of the system, how to build and run the software, and links to relevant CI/CD pipelines and related software. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. CONTRIBUTING.md
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; file can also be included with the source code to describe how to contribute to the code. &lt;code&gt;CONTRIBUTING.md&lt;/code&gt; can include brief descriptions of things like overall code organization, how to test and submit bug fixes, expectations for code comments, and more. &lt;/p&gt;

&lt;h2&gt;
  
  
  3. Checklists and Standard Operating Procedures
&lt;/h2&gt;

&lt;p&gt;Checklists and Standard Operating Procedures(SOPs) are an underrated mechanism for reducing human error and codifying important processes. Create a repository of checklists and SOPs for things like testing processes, code review steps, any manual deployment steps, and other routine tasks. &lt;/p&gt;

&lt;h2&gt;
  
  
  4. HOWTO / FAQ
&lt;/h2&gt;

&lt;p&gt;Keeping a document that details common tasks and Frequently Asked Questions (FAQs) is a great way to document team knowledge that may not fall in to a typical &lt;code&gt;README&lt;/code&gt; or &lt;code&gt;CONTRIBUTING&lt;/code&gt; document. These can be things like "how do I find logs for X", "How do I add a new service to the system?", "How Do I debug a failed deployment?" and other questions can be documented in a FAQ or HOWTO document. &lt;/p&gt;

&lt;h2&gt;
  
  
  5. Architecture Decision Records
&lt;/h2&gt;

&lt;p&gt;Architecture Decision Records (ARDs) are a great way to document not only "what" but "why" important decisions were made on how to implement important parts of a system. Documenting the evaluations and rationale of important design decisions in a lightweight format is an invaluable tool for passing down knowledge across a team. &lt;/p&gt;

&lt;p&gt;While there are many ways to document and track knowledge across a team, these are a few ideas for creating lightweight documentation that I've personally used with success across teams. What other ways have your teams successfully captured key knowledge of software and systems? &lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>A Boring Code Review is a Good Code Review</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Tue, 27 Feb 2024 05:03:27 +0000</pubDate>
      <link>https://dev.to/rytheturtle/a-boring-code-review-is-a-good-code-review-54fp</link>
      <guid>https://dev.to/rytheturtle/a-boring-code-review-is-a-good-code-review-54fp</guid>
      <description>&lt;p&gt;A ubiquitous part of the software development lifecycle (SDLC), code review is the ceremony of having peers read, evaluate, and provide feedback on changes to source code prior to integrating the changes in to the application. &lt;/p&gt;

&lt;p&gt;In my experience, teams that have effective software development processes and practices have &lt;em&gt;boring&lt;/em&gt; code reviews. Boring code reviews are achieved through a combination of automated tooling and having robust peer-review throughout the entire SDLC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Tooling
&lt;/h2&gt;

&lt;p&gt;Effective teams leverage automated tooling to automate away trivial tasks like formatting and simple code style preferences. Automated code review tasks also help to eliminate personal biases and preferences by standardizing many common aspects of writing code. Adding a linter, an automatic source code formatter, and automated static analysis tool to catch potential bugs and &lt;a href="https://en.wikipedia.org/wiki/Code_smell"&gt;code smells&lt;/a&gt; streamlines the feedback and discussions during code reviews. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Hierarchy of Peer Review for Software Development
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaaqqi5ikap80waxpzqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaaqqi5ikap80waxpzqg.png" alt="The Hierarchy of Peer Review" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inspired by &lt;a href="https://en.wikipedia.org/wiki/Maslow%27s_hierarchy_of_needs"&gt;Maslow's Hierarchy of Needs&lt;/a&gt;, the Hierarchy of Peer Review in software development outlines the key areas and relative importance of peer review throughout the SDLC. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Schema and Access Patterns&lt;/strong&gt; How is data shaped? How is data generated? How is data stored? How is the data used?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure&lt;/strong&gt; How does data flow through a system? What kinds of databases and devices does the system need to run on? How do system components communicate? How does the application scale to increased demand? &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algorithms&lt;/strong&gt; What calculations and logic need to be implemented? What business logic and functionality needs to be built in to the application? &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Architecture&lt;/strong&gt; What programming language and runtime will be used to implement the software? How will the application code be structured? What design patterns and paradigms will be used? &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt; Does the code that was written actually do what was discussed in previous steps? Is it well tested? Is it easy to read? Is it extensible for future use cases? &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By the time a pull request is submitted for code review, effective teams have already thoroughly peer reviewed everything except the implementation. While there may be minor feedback about code style or teaching people about helpful ways to write code, the rest of the content of a code review should not have anything surprising. In other words, code review on highly effective teams are &lt;em&gt;boring&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Leveraging automated tooling and building peer-review in to the entire SDLC are powerful tools for streamlining code reviews. What kinds of processes and tools have helped your teams make the code review process more effective? &lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Refactoring Toward Configurability</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Mon, 26 Feb 2024 16:00:00 +0000</pubDate>
      <link>https://dev.to/rytheturtle/refactoring-toward-configurability-5b71</link>
      <guid>https://dev.to/rytheturtle/refactoring-toward-configurability-5b71</guid>
      <description>&lt;p&gt;Designing software behavior to be configurable is an incredibly powerful tool for making software easily readable and maintainable. Configurable software behavior reduces the cost of modifying and extending application behaviors and makes it easier for engineers and non-engineers alike to read and understand application logic. This article explores the differences between application capability and behavior, outlines general steps to refactoring toward configurable behavior, and demonstrates an example of writing configurable application logic for a Mechanic Shop. &lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring Towards Configurability
&lt;/h2&gt;

&lt;p&gt;When designing application software, we must consider three aspects of the software's implementation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Capability&lt;/strong&gt; What the software is capable of doing &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavior&lt;/strong&gt; How the software behaves at runtime. Behavior can be thought of as what capabilities are executed under a particular set of circumstances.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context&lt;/strong&gt; The situational information and values that drive the software behavior. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While software capabilities need to be coded in to the implementation, software behavior can be refactored to configuration. Compared to implementing software behavior in code, making software behavior configurable offers important advantages for readability and maintainability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Configuration is concise&lt;/strong&gt; Relative to the equivalent code, configuration can eliminate hundreds of lines of code and dozens of logical branches. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration is readable&lt;/strong&gt; Reading configuration typically does not require someone to be familiar with reading code. Configuration is usually organized in to a relatively small set of files, which is easier to traverse than sprawling directories of code packages. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To design (or refactor) software behavior to be configurable, the high level process is: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify functionality where the behavioral requirements are driven by contextual information. &lt;/li&gt;
&lt;li&gt;Decide on a technology to use for implementing your configuration, along with a configuration schema. An appropriate schema will depend on the technology and means for reading the configuration. &lt;/li&gt;
&lt;li&gt;Implement application logic, capable of receiving contextual values, looking up the appropriate behavior, and executing the behavior.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Example: Mechanic Shop
&lt;/h2&gt;

&lt;p&gt;We are writing code for a mechanics shop that needs to implement different maintenance work for vehicles. When a customer brings their vehicle to the shop, the application needs to tell the mechanics what maintenance work needs to be done, the parts required for the maintenance work and charge the customer for the work. &lt;/p&gt;

&lt;p&gt;We could certainly model all of this software exclusively in code, neatly organizing our code in well-known design patterns and thoroughly unit testing the code (which we should still do!). However, even limiting our mechanic shop to a handful of vehicle makes and models, this would quickly balloon in to many classes and hundreds of lines of code. For example, here's a simple &lt;a href="http://www.plantuml.com/plantuml/uml/lP7DQW8n4CVl-nI39tq5Iy6oHLfeiQXOUXoJqGrcCvACqX9yzsOLuxgqq4FnElF_-4qo2e9UThKjS1d4en9G5aE01LL6MO9O0CIL8QiFy47eOGWlxDQjwIjkA4rduitrd3NPdnOJpJK9vQXcTMu_02f5M-a_lxFVp35iG0R5eUZYFR7J2FGfv7I6ZHsgSpVSG-zew3L9fu1okiZsKrY4nfx8Aax-FHlz9vRS_ePUsWIAWmpXaNTBIvVU1-F7nWhvtDwoGyp24rJfzrr3EoB2HJ_xSbAH63KnzlTiuv9lXOhWSbHitxqcAHFucFqHeD-yanhSTIHDOBZIL4cJMH92MQ5R4vXwQwac9w5T2F_UE3UUfYmeXjtDIlD7tEhO4Jczg-qt"&gt;UML Diagram&lt;/a&gt; implementing three types of maintenance work items for a single vehicle using a &lt;a href="https://refactoring.guru/design-patterns/visitor"&gt;visitor pattern&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1jzhb06o75kre5k38km.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl1jzhb06o75kre5k38km.png" alt="Implementing a mechanic shop" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead, we'll design our software behavior to be configurable to minimize changes as the mechanic shop expands to working on more types of vehicles. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Identify Functional Behavior Driven by Context
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;While each individual maintenance job is a core capability of the software (such as being able to change oil), the specific maintenance to perform on the vehicle is driven by the vehicle's &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt;, and &lt;code&gt;odometer&lt;/code&gt; mileage. For example, a 2023 Honda CR-V with 10,000 miles will need an oil change and tire rotation. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The parts required for any maintenance job is dependent on what the job is, and what &lt;code&gt;make&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, and &lt;code&gt;year&lt;/code&gt; the vehicle is. A Ferrari will need different oil for an oil change than a Honda. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The cost for each maintenance job performed on a vehicle will be determined from some base price and the cost of all the required parts for the job. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Pick A Technology and Schema for Configuration
&lt;/h3&gt;

&lt;p&gt;For this example, we will use &lt;code&gt;JSON&lt;/code&gt; files to encode the application's behavior and query it using &lt;a href="https://github.com/json-path/JsonPath"&gt;JSONPath&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There's more than one way to define a configuration scheme that would be suitable for encoding the configuration. Here's an example where we use a string concatenation of &lt;code&gt;&amp;lt;year&amp;gt; &amp;lt;make&amp;gt; &amp;lt;model&amp;gt;&lt;/code&gt; as the key to look up the maintenance schedule, required parts, and part costs for a particular vehicle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// config.json&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;schedule&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023 Honda CR-V&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;7500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oil_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tire_rotation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;15000&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oil_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tire_rotation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;air_filter_replacement&lt;/span&gt;&lt;span class="dl"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tasks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oil_change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023 Honda CR-V&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;synthetic_oil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oil filter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base_price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tire_rotation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023 Honda CR-V&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base_price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;air_filter_replacement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2023 Honda CR-V&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;parts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;honda_crv_air_filter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;base_price&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;part_cost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;honda_crv_air_filter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;synthetic_oil&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;oil_filter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&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;h3&gt;
  
  
  Step 3: Implement Application Logic
&lt;/h3&gt;

&lt;p&gt;We now can implement our application logic as a simple shell where the specific behavior of the application (what maintenance jobs to perform, the associated costs) is dynamically determined from our configuration based on the context of what vehicle is being worked on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppConfig&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
       &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;AppConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; 
      &lt;span class="c1"&gt;//load config to memory...&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// MaintenanceShop.java&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MaintenanceShop&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;AppConfig&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AppConfig&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"config.json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&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;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;odometer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;

    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;scheduleQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
          &lt;span class="s"&gt;"$.schedule.\"%s %s %s\".%s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;,&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;odometer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MaintenanceJob&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduleQuery&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Part&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;requiredParts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MaintenanceJob&lt;/span&gt; &lt;span class="nl"&gt;job:&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;partsQuery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$.tasks.%s.\"%s %s %s\".parts"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;,&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;requiredParts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partsQuery&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;performMaintenance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;computeTotalCharge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requiredParts&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Power of Configuration
&lt;/h2&gt;

&lt;p&gt;Having designed our code as a thin shell of capabilities who's behavior is driven by configuration and contextual information, we now have software that is simple to read and modify.&lt;/p&gt;

&lt;p&gt;If asked to figure out what Honda vehicles the maintenance shop services, we need only look at a single file. No need to dig through source code or make sense of class hierarchies to find the information. &lt;/p&gt;

&lt;p&gt;Adapting to new requirements is also far less work than dealing with complex class hierarchies. Let's imagine that our mechanic shop is very popular and we need to support many different cars. If we had implemented our application behavior directly in the code, the changes for adding a handful of new makes and models of vehicles would involve creating a dozen new classes, modifying supporting classes, and writing additional unit tests to make sure we've covered all the correct behavior in code.&lt;/p&gt;

&lt;p&gt;With our configuration, extending our application to support new cars, service types, and parts can be done in a single file with only a few lines of configuration. Configurable application behavior makes the software readable and less expensive to maintain and evolve over time.  &lt;/p&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>tutorial</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Advanced Enums in Java</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sat, 17 Feb 2024 03:03:21 +0000</pubDate>
      <link>https://dev.to/rytheturtle/advanced-enums-in-java-j6e</link>
      <guid>https://dev.to/rytheturtle/advanced-enums-in-java-j6e</guid>
      <description>&lt;p&gt;Enums are a powerful mechanism used to specify that a type is limited to one of a set of constants. In addition to simple labeling of constants, the Java implementation of Enums can be used for simplifying code and improving readability. This article will explore some advanced uses of Java Enums, including advanced type safety, defining configuration, singletons, and defining simple state machines as a directed, acyclic graph (DAG). &lt;/p&gt;

&lt;h2&gt;
  
  
  Type Safety With Constants
&lt;/h2&gt;

&lt;p&gt;The first and often only use of Enums taught to Java developers is to use it to label constant values. Not only is this a useful tool for readability by avoiding "magic constants", it is also a powerful tool for defensive programming by adding type constraints to method parameters. &lt;/p&gt;

&lt;p&gt;Consider the following function that adds an application-specific error type to the general log message for when an exception occurs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; 
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application error: %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createAccount&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; 
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;logError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Account Creation"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code has a few issues that make it difficult to maintain &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Repetition&lt;/strong&gt; if there are multiple places that log errors during account creation, we have to hope the developer knows that the correct label for the error logs is "Account Creation" and not "creating account" or "setup" or something else. This repetition is also susceptible to misspellings or inconsistent capitalization that causes issues with searching debug logs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt; Yes, the parameter has to be a &lt;code&gt;string&lt;/code&gt;, but it's not likely that &lt;em&gt;any&lt;/em&gt; &lt;code&gt;string&lt;/code&gt; is a valid input to this method. Instead, there needs to be some mechanism to limit what &lt;code&gt;string&lt;/code&gt; is acceptable as input. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can leverage Enums to address these problems&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AppErrorType.java&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;AppErrorType&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="no"&gt;ACCOUNT_CREATION&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Account Creation"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="no"&gt;PROFILE_SETUP&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Profile Setup"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="no"&gt;EMAIL_UPDATE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Email Update"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
  &lt;span class="nc"&gt;ErrorType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
  &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// some other class...&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AppErrorType&lt;/span&gt; &lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt; 
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Application error: %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                    &lt;span class="n"&gt;errorType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ... &lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createAccount&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; 
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="n"&gt;logError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AppErrorType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACCOUNT_CREATION&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using an Enum for error types, this update &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;eliminates the chances of misspellings in the error labels &lt;/li&gt;
&lt;li&gt;limits the scope of valid &lt;code&gt;string&lt;/code&gt; instead of allowing any arbitrary &lt;code&gt;string&lt;/code&gt; input to the &lt;code&gt;logError&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;eliminates the need for extra logic and tests on the method to ignore invalid &lt;code&gt;string&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;provides a single place for developers to look up what error labels are valid. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This technique can be implemented for any data type, and is a valuable tool for defensive programming where a method needs to only accept a particular set of valid values as an input.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Configuration
&lt;/h2&gt;

&lt;p&gt;Additionally, since Enums can have any number of fields, they are useful for configuring and grouping related values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="no"&gt;BASIC&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;9.99&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
        &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ADS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BASIC_CHANNELS&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
  &lt;span class="no"&gt;PREMIUM&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;21.00&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
          &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
          &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AD_FREE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BASIC_CHANNELS&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SPORTS_PACKAGE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                  &lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PREMIUM_MOVIES&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxDevices&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;includedFeatures&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Double&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Feature&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maxDevices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;includedFeatures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing Singletons
&lt;/h2&gt;

&lt;p&gt;A singleton is a class that is intended to only ever have a single instance created. Seemingly simple on the surface, implementing a thread-safe, serializable singleton in Java has several approaches that are tricky and have performance implications in multithreaded environments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// singleton with double-checked locking&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MySingleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;volatile&lt;/span&gt; &lt;span class="nc"&gt;MySingleton&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;MySingleton&lt;/span&gt; &lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;synchronized&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MySingleton&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MySingleton&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, we can leverage the fact that the Java Virtual Machine(JVM) guarantees &lt;code&gt;Enum&lt;/code&gt;s to only ever have one instance created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;MySingleton&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="no"&gt;INSTANCE&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;doSomething&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple way to leverage the JVM to ensure our singletons are thread-safe and serializable without having to repeat the same boilerplate construction and serialization logic for every singleton we create. &lt;/p&gt;

&lt;h2&gt;
  
  
  State Machines
&lt;/h2&gt;

&lt;p&gt;Many applications in software can be modeled as workflows. A workflow is a directed graph of states that can be implemented as a Finite State Machine(FSM). The FSM specifies all valid transitions from any given state. An input, called a &lt;code&gt;context&lt;/code&gt;, enters an initial state and can traverse the graph after some processing until it reaches a terminal state (a state which has no valid transitions to other states). &lt;/p&gt;

&lt;p&gt;Since Enums are classes in Java, we can use Enums to model the finite state machine with the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;define an interface for the state machine states that allows a state process a &lt;code&gt;context&lt;/code&gt; and indicate whether the current state is &lt;code&gt;terminal&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;FSMState&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="nc"&gt;FSMState&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Implement the states using an interface. the &lt;code&gt;process&lt;/code&gt; method on each state performs whatever processing is required on the context at that state and then returns the next state to transition to in the graph.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;FSMState&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="no"&gt;FIRST&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;SECOND&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;},&lt;/span&gt;
  &lt;span class="no"&gt;SECOND&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;LAST&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; 

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;},&lt;/span&gt;
  &lt;span class="no"&gt;LAST&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Define the &lt;code&gt;context&lt;/code&gt; object that will be the input throughout the state machine. A context object must contain it's own current &lt;code&gt;state&lt;/code&gt;, and implement a &lt;code&gt;process&lt;/code&gt; function that advances the context by using the &lt;code&gt;state&lt;/code&gt;. This will be driven by an external &lt;code&gt;machine&lt;/code&gt; later.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;  
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;FSMState&lt;/span&gt; &lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; 
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FIRST&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;FSMState&lt;/span&gt; &lt;span class="nf"&gt;getCurrentState&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; 
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isFinished&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isTerminal&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Define a &lt;code&gt;machine&lt;/code&gt; that initializes and drives the context through it's different states. The machine logic is really dependent on the application, but an example of how to drive a context through states looks something like
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Machine&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"current state: "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCurrentState&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isFinished&lt;/span&gt;&lt;span class="o"&gt;()){&lt;/span&gt; 
      &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"current state: "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCurrentState&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given our examples, running &lt;code&gt;Machine.main()&lt;/code&gt; results in the following output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current state: FIRST
current state: SECOND
current state: LAST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A Powerful Addition to the Toolbox
&lt;/h2&gt;

&lt;p&gt;Enums are a powerful data type, especially in Java. This article has demonstrated how Enums can be used to improve readability of code by labeling constants, restricting method inputs, and reduce boilerplate when defining Singletons and state machines. Enums are a valuable addition to any developer's mental toolbox. &lt;/p&gt;

</description>
      <category>java</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Avoiding While Loops for Safer Code</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sun, 11 Feb 2024 20:54:38 +0000</pubDate>
      <link>https://dev.to/rytheturtle/avoiding-while-loops-for-safer-code-4deb</link>
      <guid>https://dev.to/rytheturtle/avoiding-while-loops-for-safer-code-4deb</guid>
      <description>&lt;p&gt;Looping constructs that do not specify an upper bound limit for repetition, such as the &lt;code&gt;while&lt;/code&gt; loop, are the most susceptible to accidental infinite loops. Unintentionally triggering an infinite loop results in a process using increasing amounts of system resources until the process crashes, usually crashing other processes running on the same machine along with it. Using a &lt;code&gt;for&lt;/code&gt; loop with incrementing conditions as a circuit breaker to avoid infinite loops is an effective alternative to &lt;code&gt;while&lt;/code&gt; loops that more clearly communicates intent and protects production systems from runaway programs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looping constructs in code
&lt;/h2&gt;

&lt;p&gt;“Looping” in software is the ability to repeatedly execute a block of code until a particular condition is met. Most programming languages offer several different constructs for looping, such as &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;do-while&lt;/code&gt;, and others. Some programming languages have no looping constructs at all, relying on recursion to repeatedly execute code. This discussion will focus on programming languages that &lt;em&gt;do&lt;/em&gt; have looping constructs.&lt;/p&gt;

&lt;p&gt;All looping constructs are based around the concept that there is some block of code that needs to be executed repeatedly. The differentiator, beyond syntax and minor semantic details, is whether or not we know the maximum number of times that the code should be executed.&lt;/p&gt;

&lt;p&gt;An example of a loop type where we do know the maximum number of times the loop should execute is the &lt;code&gt;for&lt;/code&gt; loop. A &lt;code&gt;for&lt;/code&gt; loop has up to three expressions in it’s definition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An &lt;strong&gt;initializer&lt;/strong&gt; that is executed once before the loop begins. This usually is done to set some starting value that is incremented a fixed number of times to control the maximum number of times the loop can execute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;strong&gt;condition expression&lt;/strong&gt; that is checked before each iteration of the for loop. If the condition evaluates to false, the loop stops executing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An &lt;strong&gt;increment expression&lt;/strong&gt; that executes at the end of each iteration of the loop, before the next iteration begins.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initializer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// body&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason for saying “up to” three expressions is that most programming languages allow one or more of these expressions to be omitted. Most often, the for loop is used with all three expressions present.&lt;/p&gt;

&lt;h2&gt;
  
  
  The While Loop
&lt;/h2&gt;

&lt;p&gt;A common type of loop that is used when the number of times the loop needs to repeat is unknown is the &lt;code&gt;while&lt;/code&gt; loop. The while loop definition consists of only a condition expression. Similarly to the condition expression of a for loop, this condition expression is evaluated before each iteration of the loop, and the loop stops executing once the condition evaluates to false.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// body&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;while&lt;/code&gt; loops are commonly used when the number of times the loop needs to execute is not known ahead of time. For example, if we are traversing the nodes of a tree, we may not know exactly how many nodes are present in the tree, so a while loop may be used with a queue of tree nodes that executes until the queue is empty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;currentNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Infinite Loop Problem
&lt;/h2&gt;

&lt;p&gt;An infinite loop is the programmer’s tool to say “do this code over and over again until something purposely stops the program”. Intentional infinite loops, such as a web server listening for incoming requests, are designed in a way where the “infinite” part does not run out of control with system resources to avoid causing major problems.&lt;/p&gt;

&lt;p&gt;Unintentional infinite loops, however, typically will consume ever-growing amounts of system resources until the process or thread ultimately crashes. These resource-hungry infinite loops have a large blast radius as well, causing other processes running on the same machine to crash as the infinite loops consumes all of the system resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  For Loops as a Circuit Breaker
&lt;/h2&gt;

&lt;p&gt;The intention communicated by a while loop is that some code should be repeated until a condition is met, and the code should repeat, possibly forever, until that condition is satisfied. Most often, the more accurate intention of a developer is that the number of times the loop needs to run is not known, but it should stop before consuming all of the system resources and crashes.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;for&lt;/code&gt; loop can be used as an alternative to &lt;code&gt;while&lt;/code&gt; loops to not only communicate this intent more clearly, but also avoid infinite loops entirely. To do this, we&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;specify an upper bound limit for how many iterations the loop can repeat. This is usually an arbitrary limit found by trial and error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;write our loop as a &lt;code&gt;for&lt;/code&gt; loop with all three expressions. The initializer expression initializes a counter. The condition expression is our usual expression AND the counter has not exceeded the upper bound limit we specified. The increment expression increments the counter variable we initialized for this loop.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After our loop, check that the end condition was satisfied, and gracefully handle the situation if the maximum threshold was exceeded. “Gracefully” should, at a minimum, include logging the fact that the loop reached the maximum threshold, what the threshold was configured to at the time, and any relevant inputs that can be used to investigate the cause for hitting the upper limit of loop executions. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can take the tree traversal code from earlier and re-write it as a &lt;code&gt;for&lt;/code&gt; loop with an upper bound threshold.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; 
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;MAX_NODES_ALLOWED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;nodesVisited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
     &lt;span class="nx"&gt;nodesVisited&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;MAX_NODES_ALLOWED&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nx"&gt;nodesVisited&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nx"&gt;currentNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&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;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;too many nodes to process&lt;/span&gt;&lt;span class="dl"&gt;"&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;p&gt;Let’s examine the scenario where a tree has a cycle in it’s graph instead of behaving according to the rules of a valid binary tree.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// causes a cycle here&lt;/span&gt;
&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;startNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stepping through the code in the &lt;code&gt;while&lt;/code&gt; loop implementation, we can see that the state of the queue after each iterations is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[A]
[B, C]
[C, A]
[A]
[B, C]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;while&lt;/code&gt; loop will keep pushing and popping the same nodes to the queue until something kills the process. Usually, this will result in some messy error messages about running out of memory or processes timing out, without providing much context about what actually happened. It is highly unlikely that we intended to process the tree nodes infinitely until the system crashed.&lt;/p&gt;

&lt;p&gt;In contrast, the &lt;code&gt;for&lt;/code&gt; loop implementation put an upper bound limit of 1000 iterations of the loop. After the loop hits 1000 iterations, it stops repeating and logs an error message. This is a much better alternative that&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;doesn’t crash the current process&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;doesn’t cause other processes on the machine to crash&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gives meaningful logs for debugging the actual problem&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example code logs a simple message, but production code should log more meaningful context about what inputs and data caused the loop to exceed the upper bound threshold.&lt;/p&gt;

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

&lt;p&gt;High quality code communicates intent. The intent communicated by &lt;code&gt;while&lt;/code&gt; loops is that code should be repeated, possibly forever, until a condition is met. Most often, the real intent is that the code needs to repeat for an unknown amount of iterations, but probably should stop before crashing the entire process. Using a &lt;code&gt;for&lt;/code&gt; loop as a circuit breaker is an effective way to both avoid the possibility of infinite loop conditions and communicate an accurate intent to others reading the code.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>beginners</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Null Safety In Java</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sun, 11 Feb 2024 01:59:24 +0000</pubDate>
      <link>https://dev.to/rytheturtle/null-safety-in-java-3mde</link>
      <guid>https://dev.to/rytheturtle/null-safety-in-java-3mde</guid>
      <description>&lt;p&gt;Using Java’s Optional class provides null safe access to nested object hierarchies and chained method calls. Using &lt;code&gt;Optional.map()&lt;/code&gt; can safely wrap chained method calls without excessive if/else checks and minimize branching. This keeps code easier to read, minimizes cyclomatic complexity, and reduces the amount of unit test maintenance needed to maintain full test coverage. &lt;/p&gt;

&lt;p&gt;Introduced in Java 1.8, the Optional class gives a null safe standard library class for Java developers to express that a value may or may not be present. Null safety is an important characteristic of code, so much so that null safety is a first class feature of many newer programming languages. Java, with it’s dedication to backwards compatibility, opted to introduce a standard library container Optional to deal with null safety while maintaining backward compatibility.&lt;/p&gt;

&lt;p&gt;While Optional and Java 1.8 aren’t exactly new at the time of writing this article, I wanted to explore and showcase specifically how working with Objects and APIs that you may not be able to refactor to directly return Optional can still leverage Optional to safely access nested members. More specifically, Optional lets us safely access nested members of objects without exponentially blowing up cyclomatic complexity (basically the number of possible branches your code could execute). Minimizing cyclomatic complexity makes code easier to read and, perhaps just as importantly, minimizes the amount of “noise” in our unit test suites. &lt;/p&gt;

&lt;p&gt;Consider the following scenario:  We have a &lt;code&gt;User&lt;/code&gt; object , with various fields for properties about the user. For some reasons (they were written before Java 1.8, the classes need non optional returning getters and setters for serialization, etc) , the classes that make up the &lt;code&gt;User&lt;/code&gt; cannot be edited. The project owners in this example insist on 100% line and branch coverage with unit tests which is enforced by static analyzers that run on all merge requests. &lt;/p&gt;

&lt;p&gt;The task is to write a method in a utility class (the topic of utility classes and their merits is a topic for another time, so just go with it here…) that validates whether or not our &lt;code&gt;User&lt;/code&gt;’s zip code is local to one of our business’s physical stores. &lt;/p&gt;

&lt;p&gt;First, here are the classes for the User and it’s associated information&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User.java

//...
public class User {
    private UserName userName; 
    private Address  address;
    private PhoneNumber phoneNumber; 
    // typical getters and setters ...
}

Address.java 

//...

public class Address {
    private StreetAddress street;
    private StateAddress state; 
    // typical getters and setters ...
}

StateAddress.java

//...
public class StateAddress {
    private String city;
    private String state;
    private PostalCode postalCode; 
    // typical getters and setters
}

PostalCode.java

public class PostalCode {
    private String zip;
    private String zipPlus4;
    // typical getters and setters
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task is to write a utility function that validates the user’s zip code matches a zip code from a list of our business’ physical locations. This is the implementation of that logic (using hardcoded set of store zip codes for demonstration purposes).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// ... 
public class UserUtil {

    private static final Set&amp;lt;String&amp;gt; storeZipCodes = Stream.of("80208").collect(Collectors.toCollection(HashSet::new));

    private UserUtil(){}

    public static boolean isNearPhysicalLocation(User user) {
        String mainZip = user.getAddress()
                .getState()
                .getPostalCode()
                .getZip();

        return storeZipCodes.contains(mainZip);
    }

}


UserUtilTest.java

//...
class UserUtilTest {

   @Test void isUserNearPhysicalLocationReturnsTrueWhenSameZip() {
        User user = buildTestUserWithFullAddress();
        assertTrue(UserUtil.isNearPhysicalLocation(user), " should return 'true'");
    }

    //...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn’t seem too bad so far. This utility method has a cyclomatic complexity of 1 (meaning no branching) in isNearPhysicalLocation, and has 100% line coverage from unit tests! Seems like it’s good to pass all the static analyzers for code review and get approved by the project owners, right? &lt;/p&gt;

&lt;p&gt;Or…maybe not. This method is not null safe because if the user is null, or the user’s state field is null, or the user’s state’s postalCode field is null, then this method will throw a &lt;code&gt;NullPointerException&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;UserUtilTest.java

//...

    @Test void isUserNearPhysicalLocationReturnsFalseIfMissingPostalCode() {
        User user = buildTestUserWithFullAddress();
        user.getAddress().getState().setPostalCode(null); 
        // we get NullPointerException here!!
        assertFalse(UserUtil.isNearPhysicalLocation(user), " should return 'false'");
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how can null safety be implemented? A common approach is to add some null checks in our method to short circuit along the way. Something like this would probably get a pass from a code review for null safety.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// UserUtil.java

// ...
public static boolean isNearPhysicalLocation(User user) {
        if(Objects.isNull(user)){
            return false;
        }
        Address userAddr = user.getAddress();
        if(Objects.isNull(userAddr)){
            return false; 
        }
        StateAddress stateAddr = userAddr.getState();
        if(Objects.isNull(stateAddr)){
            return false; 
        }
        PostalCode postalCode = stateAddr.getPostalCode();
        if(Objects.isNull(postalCode)){
            return false;
        }

        return storeZipCodes.contains(postalCode.getZip());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each level of the User object is checked to makes sure we appropriately short circuit if there are some missing fields. This approach has a few problems: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It’s noisy.&lt;/strong&gt; Simple &lt;code&gt;null&lt;/code&gt; checks have more than doubled the size of the method&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cyclomatic complexity.&lt;/strong&gt; Using Codalyze to measure complexity, the cyclomatic complexity of this method increased from 1 to 5. Typical static analyzers will throw errors if the cyclomatic complexity reaches 10, and this method is halfway to that threshold just to safely access a field in an object that is a few levels deep. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unit test coverage.&lt;/strong&gt; The extra possible branches of code that can execute here has also added more scenarios that must be covered by unit tests. According to Jacoco, test coverage has dropped to 80% of lines and only 50% of branches. 4 additional unit tests are needed to get all of the branches of code covered for this method.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So adding null safety to this very simple method has exploded the amount of required unit tests, lines of code, and cyclomatic complexity. Time to refactor to achieve the same &lt;code&gt;null&lt;/code&gt; safety using Optional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// UserUtill.java 

// ...
public static boolean isNearPhysicalLocation(User user) {
    Optional&amp;lt;String&amp;gt; zip = Optional.ofNullable(user)
                            .map(u -&amp;gt; u.getAddress())
                            .map(a -&amp;gt; a.getState())
                            .map(s -&amp;gt; s.getPostalCode())
                            .map(p -&amp;gt; p.getZip());
    return storeZipCodes.contains(zip.orElse(""));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Optional.map&lt;/code&gt; checks if the Optional has a value, and only runs the supplied mapping function if the value is present. If the Optional has no value, the map function returns an empty Optional. The &lt;code&gt;orElse&lt;/code&gt; method returns the value in the Optional if it’s present, or the supplied value if the Optional is empty. &lt;/p&gt;

&lt;p&gt;This method now safely traverses a deep object structure without adding noise to the logic with null checks, maximizing readability and safety while minimizing cyclomatic complexity. As an added bonus, this approach gives us 100% line and branch coverage from the unit tests without needing to explicitly test for null checks at each level! &lt;/p&gt;

&lt;p&gt;Using Optional wisely is a great way to tame cyclomatic complexity and exponential test suite expansion while still defensively programming against &lt;code&gt;null&lt;/code&gt; references. This is especially helpful if you have chained method calls, such as when traversing a deep object structure, where refactoring the method signatures to return Optional isn’t feasible.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>java</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Taming Complexity and Code Bloat with Lookup Tables</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Sun, 11 Feb 2024 01:24:16 +0000</pubDate>
      <link>https://dev.to/rytheturtle/taming-complexity-and-code-bloat-with-lookup-tables-3h9a</link>
      <guid>https://dev.to/rytheturtle/taming-complexity-and-code-bloat-with-lookup-tables-3h9a</guid>
      <description>&lt;p&gt;The lookup table pattern is an efficient, maintainable design pattern to reduce complexity in software. Lookup tables maintain a constant cyclomatic complexity and allow related concepts to be neatly organized in a way easy to read, write, and maintain. Lookup tables can be easily represented in most programming languages regardless of paradigms such as functional, object-oriented, and others. Lookup tables minimize the code maintenance burden compared to alternative approaches, specifically if-else and the popular object-oriented alternative to if-else: polymorphism. For these reasons, the lookup table pattern should be the first choice approach unless the complexity of the domain model makes polymorphism a more suitable approach.&lt;/p&gt;

&lt;p&gt;Cyclomatic complexity is the measure of how many different branches or paths a particular piece of software can execute. Cyclomatic complexity is a language agnostic industry standard as one of the measures of maintainability of software. Most software deals with decision points where one of several paths must be taken based on some condition. Not surprisingly, most programming languages have a concept of conditional statements, also known as flow control. Usually, these come in the form of either the if-else statement or switch statements. For example, the following code has a cyclomatic complexity of 4 since there are 4 possible unique paths the code can executed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if(car.make == "Honda"){
    console.log("The power of dreams")
} else if(car.make == "Toyota"){
    console.log("Let's go places")
} else if(car.make == "Mazda"){
    console.log("Zoom zoom")
} else {
    console.log("Just a car")
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These constructs are what I would consider fundamental to the concept of programming, but, as most things do, they have some drawbacks in practice&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Each branch in an if-else block increases the cyclomatic complexity of it’s surrounding scope. A relatively tame method will quickly approach the limits of acceptable complexity for any non-trivial logic. This is especially true for nested if-else statements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The number of unit tests required to maintain line and branch coverage grows proportionally with the number of conditions in the if-else block. This is directly caused by the cyclomatic complexity problem because new cases require new code paths and new code paths require new unit tests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if-else blocks cause repetitive code. Software that makes many different decisions based on the same conditions will usually end up having the same if(someCondition()){} else {} boilerplate copied all over the place. If a required new scenario is added (which we will explore in a bit) such as a new type of user, every conditional block referencing the user type as the condition for the if-else statement must be identified and updated. Even with the help of modern IDEs, this is error prone and tedious. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the object-oriented world, a common remedy prescribed for these problems is to use polymorphism. Polymorphism means that an object can take different forms depending on the situation. Refactoring if-else to classes using polymorphism typically involves creating a series of classes to represent the different paths of code&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;an abstract base class, representing the scenario&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;one or more implementations of the abstract base class, each representing one of the branches in an if-else statement. These concrete classes are where the logic is implemented that otherwise would have been the body of one of the branches of the if-else.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a factory class (usually an abstract factory as well), that can take an input and return a concrete implementation of the abstract base class. Which implementation gets returned depends on logic that resides in the factory class. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For developers who have worked in heavily object-oriented environments such as Java, the concept of polymorphism is probably not new. Robert Martin’s book “Clean Code” prescribes polymorphism as the default answer to any scenario that would otherwise use if-else. A blog post that made it’s way around social media a few years back, &lt;em&gt;If-Else Is a Poor Man’s Polymorphism&lt;/em&gt;, is less subtle about their support for polymorphism as an alternative to if-else.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We can easily stop here and call it a day. You refactored the nasty branching out and replaced it with polymorphism. Your code is now object-oriented and incredibly easy to maintain. Great job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Polymorphism does reduce cyclomatic complexity, improve the readability of individual methods, shrink the size of each class, and provides a mechanism for some level of reusability of conditional logic. These benefits come at a price:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Polymorphism is expensive to write. It’s rarely taken seriously as a drawback to polymorphism in discussions of “clean code” and “maintainability”. Writing an abstract base class, implementation classes of the base class for each condition, and a factory to create the implementations based on some condition which still ends up using if-else anyways, and writing all of the associated unit test classes and unit tests, is a lot of code to write to ultimately achieve a fairly simple task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Polymorphism is expensive to read. Code is generally harder to read than it is to write. Given how expensive it is to write polymorphic code, it should not be a surprise that reading and understanding polymorphic code is expensive as well. Each individual polymorphic class is simple to read, but the effort to identify and understand the broader picture is dramatically complicated even in simple examples.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Polymorphism is expensive to maintain. The number of code branches with if-else increases proportionally with the number of conditions. With polymorphism, the number of classes in the code increases proportionally with the number of conditions. If you work on a moderately sized domain model and lean heavily in to polymorphism as the approach to branching and decision logic, you’ll soon find yourself digging through a sea of classes and factories, drawing impressive looking class diagrams, and discussing substantial refactorings to accommodate minor changes to functional requirements. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Polymorphism has a time and place, but it should not be the default answer to the situation where code needs to execute one of several branches of logic based on some criteria.&lt;/p&gt;

&lt;p&gt;The lookup table shines where if-else and polymorphism fall short. A lookup table is exactly what it sounds like: a table that you can use to look things up based on some criteria. When implemented in code, lookup tables are usually implemented as arrays, hashtables or hashmaps, or dictionaries. Conditions of an if-else are entries in the lookup table. The body of the if-else conditions are the values associated to the entries in the lookup table.&lt;/p&gt;

&lt;p&gt;Lookup tables have several properties that make them a convenient alternative to if-else and polymorphism:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lookup tables are inexpensive to write.&lt;/strong&gt; Lookup tables require very little “noise” to implement. Most popular languages, including Javascript and Python, have concise syntax for initializing dictionary data structures. The logic for most lookup table implementations has a cyclomatic complexity of 2 (the key exists in the lookup table so use it’s value, or the key does not exist in the table) and that complexity remains constant regardless of the number of entries in the lookup table. The only unit tests required to achieve full branch and line coverage of a method that references a lookup table are tests to verify the behavior of if a key is found and if a key is not found. There is no need to write unit tests that test for every possible key in the lookup table.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lookup tables are inexpensive to read.&lt;/strong&gt; Lookup table definitions present a clear mapping between input keys and the associated values without the extraneous classes and boilerplate of a polymorphic approach. In contrasts to the polymorphic approach, all of the conditions and values for a lookup table are grouped together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lookup tables are inexpensive to maintain.&lt;/strong&gt; Adding new conditions to existing lookup tables typically involves writing one or two lines of code. Regardless of the number of entries in the table, the only branches to test are “the value is present” or “the value is not present”, so adding extra unit tests for each new condition in the table is unnecessary. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Starting with a simple example, consider a scenario where we need to determine the price of a subscription for a streaming service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Subscription { 
  public enum TIER {
    BASIC, PREMIUM, PLATINUM
  }

  private TIER tier;

  public double getMonthlyFee(){
    switch(this.tier){
      case BASIC:
        return 10.0; 
      case PREMIUM:
        return 14.0;
      case PLATINUM:
        return 20.0;
      default:
        throw new RuntimeException("No fees for tier {tier}");
  }
}

// in some other class.....
Subscription userSubscription = //...; 
double monthlyFee = userSubscription.getMonthlyFee();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty simple situation. Our switch statement causes us to have 4 different branches of execution in the getMonthlyFee() method but all in all, it’s pretty readable.&lt;/p&gt;

&lt;p&gt;Here’s the same logic implemented in a polymorphic approach&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// remember in java these each are in separate class files ....

public enum SubscriptionTier {
  BASIC,PREMIUM, PLATINUM
}

public abstract class Subscription {   
  abstract double getMonthlyFee();
}

public class BasicSubscription implements Subscription {
  @Override
  public double getMonthlyFee(){
    return 10.0;
  }
} 

public class PremiumSubscription implements Subscription {
  @Override
  public double getMonthlyFee(){
    return 14.0;
  }
} 

public class PlatinumSubscription implements Subscription {
  @Override
  public double getMonthlyFee(){
    return 20.0;
  }
} 

public interface ISubscriptionFactory {
  Subscription makeSubscription(SubscriptionTier t);
}

public class SubscriptionFactory implements ISubscriptionFactory { 

  @Override
  public Subscription makeSubscription(SubscriptionTier t){
    switch(this.tier){
      case BASIC:
        return new BasicSubscription();
      case PREMIUM:
        return new PremiumSubscription();
      case PLATINUM:
        return new PlatinumSubscription();
      default:
        throw new RuntimeException("No fees for tier {tier}");
    }
  }
}

// somewhere else in the code...
ISubscriptonFactory factory = new SubscriptionFactory();

Subscription userSubscription = factory.makeSubscription(user.getSubscriptionTier()); 

double monthlyFee = userSubscription.getMonthlyFee();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets see the same logic using a lookup table&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Subscription { 
  public enum TIER {
    BASIC, PREMIUM, PLATINUM
  }

  private TIER tier;
  static final Map&amp;lt;TIER, Double&amp;gt; tierFees; 
  static {
    tierFees = new HashMap&amp;lt;&amp;gt;();
    tierFees.put(BASIC, 10.0);
    tierFees.put(PREMIUM, 14.0);
    tierFees.put(PLATINUM, 20.0);
  }

  public double getMonthlyFee(){
    return Optional.ofNullable(tierFees.get(tier))
      .orElseThrow(() -&amp;gt; new RuntimeException("Unknown tier"));
  }
}

// in some other class.....
Subscription userSubscription = //...; 
double monthlyFee = userSubscription.getMonthlyFee();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simple cases like these, the lookup table is great at achieving a high degree of readability, low cyclomatic complexity that doesn’t increase with additional cases or types, and does not bloat the code by spreading the configuration across numerous classes.&lt;/p&gt;

&lt;p&gt;The example in &lt;em&gt;If-Else is a Poor Man’s Polymorphism&lt;/em&gt; can also be written using lookup tables. Admittedly, this is uglier in languages that don’t have lambdas or first class functions, but I decided to write up the example scenario in Typescript to demonstrate that lookup tables are powerful beyond simple mappings between types and scalar values.&lt;/p&gt;

&lt;p&gt;Recreating the example from &lt;em&gt;If-Else is a Poor Man’s Polymorphism&lt;/em&gt; in Typescript, here’s the “complicated, headache inducing branching” logic for deciding what to do when a user is updated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum UserUpdatedReason {
    AddressChanged,
    UsernameChanged,
    EmailChanged, 
    EnabledTwoFactor
}

function UpdateAsync(reason: UserUpdatedReason , user: User) {
    if(reason == UserUpdatedReason.AddressChanged) {
      informMarketing();
      updateUser();
    } else if(reason == UserUpdatedReason.UsernameChanged){
      updateProfileSlug();
      notifyFollowers();
      updateUser();
    } else if(reason == UserUpdatedReason.EmailChanged){
      generateSecurityStamp();
      notifyMarketing();
      updateUser();
    } else if(reason == UserUpdatedReason.EnabledTwoFactor){
      generateSecurityStamp();
      updateUser(); 
    } else {
      throw new Error("Unknown reason");
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty bad, we have a cyclomatic complexity of 5 and thats a lot of code to write and read. So what does the polymorphic approach look like?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum UserUpdatedReason {
    AddressChanged,
    UsernameChanged,
    EmailChanged, 
    EnabledTwoFactor
}

interface IUserUpdatedReason{
    updateUser(u: User)
};

class AddressChanged implements IUserUpdatedReason { 
    updateUser(u: User) {
        informMarketing();
        updateUser();    
    }
}

class UsernameChanged implements IUserUpdatedReason {
    updateUser(u: User) {
        updateProfileSlug();
        notifyFollowers();
        updateUser();
    }
}

class EmailChanged implements IUserUpdatedReason { 
    updateUser(u: User) {
        generateSecurityStamp();
        notifyMarketing();
        updateUser();
    }
}

class EnabledTwoFactor implements IUserUpdatedReason { 
    updateUser(u: User) {
        generateSecurityStamp();
        updateUser(); 
    }
} 

function UpdateAsync(reason: IUserUpdatedReason , user: User) {
    reason.updateUser(user);
} 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is translated almost directly from the author’s C# example to Typescript. It conveniently leaves out the extra boilerplate for initializing each class, the factory class that would be needed to generate the IUserUpdatedReason implementations based on some criteria, and is just about complicated enough logic to where the polymorphism is a reasonable suggestion. So how would a lookup table handle this same scenario?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum UserUpdatedReason {
    AddressChanged,
    UsernameChanged,
    EmailChanged, 
    EnabledTwoFactor
}

const USER_UPDATE_TASKS: Map&amp;lt;UserUpdatedReason, Array&amp;lt;(u:User)=&amp;gt;void&amp;gt;&amp;gt; = new Map ([
    [UserUpdatedReason.AddressChanged, 
        [informMarketing, updateUser]],
    [UserUpdatedReason.UsernameChanged, 
        [updateProfileSlug, notifyFollowers, updateUser]],
    [UserUpdatedReason.EmailChanged, 
        [generateSecurityStamp, notifyMarketing, updateUser]],
    [UserUpdatedReason.EnabledTwoFactor, 
        [generateSecurityStamp, updateUser]]
])

function UpdateAsync(reason: UserUpdatedReason , user: User) {
    if(USER_UPDATE_TASKS.has(reason)){
        USER_UPDATE_TASKS.get(reason)?.forEach(task =&amp;gt; task(user))
    } else {
        throw Error("Unknown task")
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve expressed the same complex logic as the polymorphism with literally half the code, and still maintained the ability to easily add new cases without increasing the size of our code with extra classes and boilerplate.&lt;/p&gt;

&lt;p&gt;Both polymorphism and lookup tables can be used to improve the problems of if-else statements. Polymorphism is heavily object oriented and comes with the cost of dramatically increased amount of code to read, write, and maintain. Lookup tables are an efficient alternative to polymorphism that should be the first choice for developers when implementing or refactoring conditional logic. Polymorphism should be reserved for scenarios where the complexity of the cases is great enough to justify the additional cost. &lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How Mental Models Influence Software Design</title>
      <dc:creator>RyTheTurtle</dc:creator>
      <pubDate>Fri, 09 Feb 2024 17:12:57 +0000</pubDate>
      <link>https://dev.to/rytheturtle/how-mental-models-influence-software-design-mff</link>
      <guid>https://dev.to/rytheturtle/how-mental-models-influence-software-design-mff</guid>
      <description>&lt;p&gt;The shared language, relationships, and framework of thought, collectively referred to as a "mental model", is the foundation for how we think about the world around us. In software development, the "world" is the application domain that we're working in. These domains can range from high level business applications such as ecommerce stores and insurance adjustment software, to "low level" application domains like device firmware and networking infrastructure.&lt;/p&gt;

&lt;p&gt;Deciding which design patterns, paradigms, and software architecture are "right" for a particular application heavily depends on the mental model of the domain. Regardless of the domain, highly effective software development teams design and implement software in a way that closely matches the mental model of the domain. A mismatch between the mental models of the domain and the software implementation leads to systems that are difficult to understand, maintain, and evolve over time. This concept is commonly understood and explained when discussing the &lt;a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_impedance_mismatch"&gt;object-relational impedance mismatch&lt;/a&gt; problem between Object Oriented Design and relational databases. The same concept applies to the mismatch between the mental model of the application domain and the implementation model of the software. &lt;/p&gt;

&lt;p&gt;To illustrate this concept, we can observe how two different mental models of the same domain can lead to two different implementation decisions to solve the same problem. The only deciding factor of which approach is "correct" is whether the implementation matches the mental model of the domain shared throughout the team and organization.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Case Study: Implementing Coffee Shop Menu Pricing
&lt;/h2&gt;

&lt;p&gt;The book &lt;em&gt;Head First Design Patterns&lt;/em&gt; uses the concept of a coffee shop ordering application as an example to illustrate the implementation of the decorator pattern. The author makes the decision to implement the decorator pattern based on their mental model of the coffee shop, but we can examine how a different mental model would dramatically change how we approach the task of ordering coffee. &lt;/p&gt;

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

&lt;p&gt;In the coffee shop example, the application needs to be able to take a customer's order for a beverage and accurately calculate the price of the beverage. This needs to be implemented in a scalable way to handle updates to the coffee shop's menu over time. The menu of the coffee shop looks something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Coffees:
  House Blend: 0.89
  Dark Roast:  0.99
  Decaf:       1.05
  Espresso:    1.99

Condiments:
  Steamed Milk: 0.10
  Mocha:        0.20
  Soy:          0.15
  Whip:         0.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mental Model 1: Condiments Are The Beverage
&lt;/h3&gt;

&lt;p&gt;In &lt;em&gt;Head First Design Patterns&lt;/em&gt;, the author's mental model treats every combination of beverage and condiments as a unique beverage. For example, a "double soy mocha latte" is considered a different beverage than "mocha latte with whip cream". &lt;/p&gt;

&lt;p&gt;Using this mental model, the author goes on to illustrate how the decorator pattern can be used to implement the pricing logic. The detailed explanation of the decorator pattern is beyond the scope of this article, but the end result is that an order such as "house blend with soy mocha and whip cream" can be expressed with something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abstract class Beverage { 
    abstract double getCost();
}

public class HouseBlend extends Beverage { 
    public double cost(){ 
        return 0.89;
    }
}

abstract class CondimentDecorator extends Beverage { 
    Beverage beverage; 
}

public class Mocha extends CondimentDecorator { 
    public Mocha(Beverage b){ 
        this.beverage = b;
    }

    public double cost() {
        return beverage.cost() + .20; 
    }
}

public class WhipCream extends CondimentDecorator { 
    public Mocha(Beverage b){ 
        this.beverage = b;
    }

    public double cost() {
        return beverage.cost() + .10; 
    }
}


public class Soy extends CondimentDecorator { 
    public Mocha(Beverage b){ 
        this.beverage = b;
    }

    public double cost() {
        return beverage.cost() + .15; 
    }
}

// a soy mocha coffee with whip cream
Beverage order = new HouseBlend();
Beverage addedSoy = new Soy(order);
Beverage addedMocha = new Mocha(addedSoy);
Beverage addedWhip = new Whip(addedMocha);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each condiment decorator creates a new object (literally and conceptually) that has it's own unique definition of it's cost. The condiments are an input in to what beverage the customer is ordering, but condiments are not first-class entities. If the mental model of the team and business is that every combination of condiment and coffee is a unique beverage, this would be a perfectly acceptable approach to implementing the fictional coffee shop pricing logic.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Mental Model 2: A Beverage Consists of Condiments
&lt;/h3&gt;

&lt;p&gt;Looking at the menu of items in the fictional coffee shop, both Condiments and Coffees are their own sections of the menu. Taking a cue from the menu, it's easy to see how someone would develop the mental model of a beverage being one of the coffees, with condiments being an entirely separate concept. In this mental model, condiments can be added to a beverage, but are not themselves tied to the definiton of a beverage. This mental model might be more applicable if our fictional customers are allowed to order condiments directly, such as ordering a cup of whip cream to give to their dog as a treat. &lt;/p&gt;

&lt;p&gt;With this mental model, if we kept the approach of using the decorator pattern to represent every combination of coffee and condiments as a distinct beverage, a developer reading the code would likely struggle to understand the structure and make changes to it correctly as new requirements evolved. However, a structure that treats condiments separately , modeled below, would more closely repesent this mental model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abstract class Beverage { 
    protected List&amp;lt;Condiment&amp;gt; condiments = new ArrayList&amp;lt;&amp;gt;();
    protected double price; 

    public void addCondiment(Condiment c){ 
        this.condiments.add(c);
    }

    public double getCost() { 
        double cost = this.price;
        for(Condiment c: condiments){ 
            cost += c.price();
        }
        return cost;
    }
}

public class HouseBlend extends Beverage { 
    public HouseBlend(){ 
        this.price = 0.89;
    }
}

public enum Condiment { 
  SOY(0.15),
  MOCHA(0.20),
  WHIP(0.10)

  public final double price;

  Condiment(double price) { 
    this.price = price;
  }
}


Beverage order = new HouseBlend();
order.addCondiment(SOY);
order.addCondiment(MOCHA);
order.addCondiment(WHIP);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Which design is "correct"?
&lt;/h3&gt;

&lt;p&gt;The answer is "it depends". In either scenario, if the code reflects the mental model of beverages and condiments that is used by the domain experts, it's a good design choice. When code reflects the mental model used by the developers, it's (usually) the correct choice because there is little translation that has to be done between the mental model used when communicating to stakeholders and the logic that is expressed in the code. Choosing designs, architectures, and paradigms that match the shared mental model of the domain is a key factor in writing code that can be easily understood and maintained over time. &lt;/p&gt;

</description>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>productivity</category>
      <category>java</category>
    </item>
  </channel>
</rss>
