<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Joe Cannatti</title>
    <description>The latest articles on Forem by Joe Cannatti (@joecannatti).</description>
    <link>https://forem.com/joecannatti</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%2F132949%2F85b17da6-2ea8-4b87-ab11-7b268663dd14.png</url>
      <title>Forem: Joe Cannatti</title>
      <link>https://forem.com/joecannatti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joecannatti"/>
    <language>en</language>
    <item>
      <title>Mentoring With Personality In Mind</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Fri, 21 Jun 2019 15:28:12 +0000</pubDate>
      <link>https://forem.com/joecannatti/mentoring-with-personality-in-mind-5fao</link>
      <guid>https://forem.com/joecannatti/mentoring-with-personality-in-mind-5fao</guid>
      <description>&lt;p&gt;I try to approach most interactions with my teammates as a mentoring opportunity. Sometimes this means simple stuff like showing them a command-line trick or a design pattern.&lt;/p&gt;

&lt;p&gt;It can also get pretty subtle though.&lt;/p&gt;

&lt;p&gt;For example, I recently heard myself say to a less experienced engineer,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Are you sure you aren’t being too careful?”&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Me to a less experienced engineer&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think it was a useful question to ask in that specific situation, but afterwards I found myself reflecting about it. I wasn’t 100% that was the best thing to say.&lt;/p&gt;

&lt;p&gt;I don’t think it’s useful for a mentor to try to shape the personality of their mentee to be more like their own.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don’t think it useful for a mentor to try to shape the personality of their mentee to be more like their own.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Joe Cannatti – me&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To some extend, I think that’s what I was doing in that case. I had an instinct going off in my head that we were being too careful about a decision, but that was my own person reaction to the situation.&lt;/p&gt;

&lt;p&gt;The goal of being a mentor isn’t to shape someone’s instincts and style to match your own. It’s to help someone do their best work given their personality and instincts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The goal of being a mentor isn’t to shape someone’s instincts and style to match your own. It’s to help someone do their best work given their personality and instincts.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Joe Cannatti – me&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, that could still mean that it was the right call to help guide this person in a different direction. However in this case, I don’t think their reaction was coming from a misunderstanding of the elements of the decision or a lack of experience. I think they just felt differently than I did about the situation because of their personality and temperament.  &lt;/p&gt;

&lt;p&gt;A possible better approach could be to say something like, “I feel like we are being a bit too careful about this. What thoughts and feelings are you working with as we discuss this issue? Do you understand all the key points of the situation? I want to make sure you’re using your efforts in the way that’s most effective for you.”&lt;/p&gt;

&lt;p&gt;It’s a subtle change in language, but it’s a different message.  &lt;/p&gt;

&lt;p&gt;I challenge both mentors and mentees to work with this idea. Can you separate reactions that come from personality and temperament from ones that come from knowledge and experience?   &lt;/p&gt;

&lt;p&gt;Leave a comment below or reach me on Twitter &lt;a href="https://twitter.com/JoeCannatti"&gt;@joecannatti&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>career</category>
    </item>
    <item>
      <title>Humans Can Code Too: Idempotency</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Wed, 19 Jun 2019 02:20:55 +0000</pubDate>
      <link>https://forem.com/joecannatti/humans-can-code-too-idempotency-42jc</link>
      <guid>https://forem.com/joecannatti/humans-can-code-too-idempotency-42jc</guid>
      <description>&lt;p&gt;Humans Can Code Too is a content series aimed at anyone who is not coming from a traditional computer science background and is trying to gain a better understanding of software development. This includes those who are just getting starting in a programming career, as well as business people who just want to understand what the hell developers are talking about.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s a scary term
&lt;/h2&gt;

&lt;p&gt;Idempotency is a very intimidating word to have someone drop on you in a Pull Request or code review. It sounds super sophisticated and scientific, mathematical even.&lt;/p&gt;

&lt;p&gt;The word “idempotency” does come from higher math. However, what a software developer means when they use the word is nothing super complicated.&lt;/p&gt;

&lt;p&gt;I’ll give it my own definition&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Idempotency – n&lt;/p&gt;

&lt;p&gt;When a piece of code can be run multiple times with the same input data without causing undesirable consequences.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Joe Cannatti — ME&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In practice, this has to do with what’s going to happen if we find ourselves in a situation where we don’t know if a unit of work was run or not. If the code is idempotent, we can simply run it again. If it’s the second (or 10000th) time it’s been run, that’s fine. It doesn’t cause any problems.&lt;/p&gt;

&lt;p&gt;This most often comes up in message-passing based systems and background jobs because those systems involve queues of work. Those queues can result in running code multiple times for a bunch of different reasons. That said, it can be an important feature in almost any situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conceptual Example
&lt;/h2&gt;

&lt;p&gt;At a conceptual level, here’s an example of a non-idempotent way to think about a unit of work followed by an idempotent version.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pay $100 to the user whose ID is 123&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;not idempotent&lt;/cite&gt;&lt;/p&gt;

&lt;p&gt;Payout the money for transaction with ID 456&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;idempotent! Great job&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  So, what’s the difference between those two?
&lt;/h3&gt;

&lt;p&gt;In the first case, there’s no way to know if the job is a duplicate or not, so if we run that job 3 times, we’re going to send them $300. Businesses usually don’t want to give away extra money&lt;/p&gt;

&lt;p&gt;In the second case, on the first run of the code it can say, “Yep, we haven’t sent that money yet, I’ll do it now”, and then on every subsequent run it can say, “Hey, I already did that, I’ll just do nothing”. So you can run that job 1 to infinite times and get the same result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p-wSiKjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/06/idempotency.png%3Fw%3D680" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p-wSiKjk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/06/idempotency.png%3Fw%3D680" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Pre-calculating Review Count
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;increment_review_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
  &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;review_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
  &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s not Idempotent! If you run that code 100 times you’re going to increase the review code by 100!  &lt;/p&gt;

&lt;p&gt;Let’s try a safer example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_review_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt; 
  &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;review_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; 
  &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ah, sweet relief. That one is way better. If you run that 100 times you’re still going to get the right result. The drawback in this example is that it’s also going to be much slower since it needs to read the reviews from the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Payouts
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
  &lt;span class="no"&gt;Xtripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xtripe_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we discussed earlier, this is no-good because there’s no way for this code to make sure this money hasn’t already been sent. We can use a transaction record to make this idempotent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;payout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;should_be_payed?&lt;/span&gt; 
    &lt;span class="no"&gt;Xtripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_payment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xtripe_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                        &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_paid!&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That little &lt;code&gt;transaction.should_be_payed?&lt;/code&gt; makes all the difference. That method can check if the transaction has already been paid out, as well as check for other conditions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: Backup to S3 (cloud based file system)
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;backup_to_s3&lt;/span&gt; 
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;S3&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The problem with this one is that if your job dies part way through, there’s no way to know where we left off without checking in S3.&lt;/p&gt;

&lt;p&gt;One way to fix it is to record a timestamp&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;backup_to_s3&lt;/span&gt;
  &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'last_backed_up &amp;lt; ?'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;week&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; 
    &lt;span class="no"&gt;S3&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;content: &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last_backed_up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt; 
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save!&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We could run this job over and over again and it’s never going to do anything unexpected! That’s what idempotency is all about!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>OKRs from a development team’s perspective</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Fri, 24 May 2019 18:17:54 +0000</pubDate>
      <link>https://forem.com/joecannatti/okrs-from-a-development-team-s-perspective-4g17</link>
      <guid>https://forem.com/joecannatti/okrs-from-a-development-team-s-perspective-4g17</guid>
      <description>&lt;p&gt;Most of the companies I’ve worked for in the last 5 years have used the OKR system. Although this system was invented in the 70s, it has more recently become popular at Google and has spread through the tech world.&lt;/p&gt;

&lt;p&gt;It’s a simple system where the company defines a number of Objectives, and each objective has one or more measurable Key Results. Those KRs are intended to track progress on that objective over time.&lt;/p&gt;

&lt;p&gt;For example.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Objective – Increase Customer Retention&lt;/li&gt;
&lt;li&gt;Key Result #1 – Lifetime Customer value increase from $N to $N+5&lt;/li&gt;
&lt;li&gt;Key Result #2 – Decrease Customer Churn Rate by 10%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most companies I’ve been at usually have 3-5 OKRs active at any given time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What OKRs are supposed to do for a company
&lt;/h3&gt;

&lt;p&gt;The idea is basically that everyone has some very clear, direct and measurable goals to align behind. Everything a team does should align to a specific OKR. In theory, that means everyone is rowing in the same direction(s).&lt;/p&gt;

&lt;p&gt;It works great at certain levels and in certain ways. For the leadership team, it typically seems to be an excellent mechanism. It can put all the leaders on the same page(s) and provide a great starting point for the quarter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It can put all the leaders on the same page(s) and provide a great starting point for the quarter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  When it comes time for a dev team make decisions…
&lt;/h3&gt;

&lt;p&gt;Where OKRs become less useful is within the decision making process for an individual team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where OKRs become less useful is within the decision making process for an individual team.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;Joe Cannatti&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The most common pattern I’ve seen goes like this&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The team comes in with a backlog of things that they want to work on.&lt;/li&gt;
&lt;li&gt;They discuss each item and work out a basic list ordered by priority. The cut out things they know they aren’t going to get to any time soon.&lt;/li&gt;
&lt;li&gt;They go over the list and add a label to each task/project to specify the OKR to which it is most closely related.&lt;/li&gt;
&lt;li&gt;For the most part, it’s usually works out to be possible to assign an OKR to anything without too much mental gymnastics&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Wait a minute… Isn’t that backwards?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Shouldn’t we be using the OKRs to drive coming up with ideas in the first place instead of just wedging them in afterwards?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yeah, I think that’s the idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  Backlog
&lt;/h3&gt;

&lt;p&gt;It usually seems to me that the reason it works out this way is because teams generally have large backlogs of things they’ve decided they’d like to do. Most of the stuff in that backlog was written down long before the current OKRs where specified.&lt;/p&gt;

&lt;p&gt;So it makes sense that when the OKRs come out for the quarter, we just take what we already have and figure out how to fit it into the OKRs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there anything wrong with that?
&lt;/h3&gt;

&lt;p&gt;Yes and no.&lt;/p&gt;

&lt;p&gt;The biggest problem seems to me to be that the team doesn’t end up feeling truly connected or committed to the OKRs. For example, as I write this, I can tell you every project we are going to attempt to work on this quarter, but I can’t even tell you what the OKRs for the quarter are.&lt;/p&gt;

&lt;p&gt;We did make them all fit in with OKRs, but it never felt like it was really what was driving us. Maybe that’s okay, but it doesn’t seem super useful to me. I think it gives leadership the justification they need to declare that everyone is working towards the same goals, but I don’t think it leads to dev teams actually feeling like that’s true.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think it gives leadership the justification they need to declare that everyone is working towards the same goals, but I don’t think it leads to dev teams actually feeling like that’s true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Ideas to improve how this all works
&lt;/h3&gt;

&lt;p&gt;I have a couple ideas about how you can make this better for the next planning cycle for your team.&lt;/p&gt;

&lt;h4&gt;
  
  
  Backlog Bankruptcy
&lt;/h4&gt;

&lt;p&gt;When you start the planning for your next cycle, consider abandoning your current backlog. Instead of diving into the things your team has already defined as work that should be done, start totally from scratch.&lt;/p&gt;

&lt;p&gt;Drive downward from the OKRs and see if the team can come with ideas that have not already been thought of. Or if they can reframe their existing ideas in meaningful ways to make them truly feel like an extension of the OKRs.&lt;/p&gt;

&lt;p&gt;This isn’t easy to do. You will need to continually push people away from stuff that’s already in the backlog, but I think it can lead to better results in the end.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use OKRs to drive weekly team meetings
&lt;/h4&gt;

&lt;p&gt;Use the OKRs as the starting point for your weekly sprint plannings and other checkin meetings.&lt;/p&gt;

&lt;p&gt;Generally, these meetings will naturally follow a pattern of being shaped by the projects and tasks people are working on, but it’s possible to keep pushing the flow of the conversation back to the OKRs.&lt;/p&gt;

&lt;h3&gt;
  
  
  What effect would this have on your team?
&lt;/h3&gt;

&lt;p&gt;I’d love to hear how you think this could workout on your team. What do you expect would be different if you adopted these techniques? Comment below or reach me at &lt;a href="mailto:joe@zafulabs.com"&gt;joe@zafulabs.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>agile</category>
      <category>motivation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What Biz People Need to Know about Tech: Configurable App Platforms</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Thu, 16 May 2019 22:10:07 +0000</pubDate>
      <link>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-configurable-app-platforms-21ba</link>
      <guid>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-configurable-app-platforms-21ba</guid>
      <description>&lt;p&gt;This is an installment in the &lt;a href="https://dev.to/joecannatti/what-biz-people-need-to-know-about-tech-series-intro-3alj-temp-slug-879578"&gt;What Biz People Need to Know About Tech&lt;/a&gt; series. It’s aim is to help non-technical business people to communicate better with engineers and provide better feedback about the value they want them to deliver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NKlu87BL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/05/adobestock_113847700.jpeg%3Fw%3D680" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKlu87BL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/05/adobestock_113847700.jpeg%3Fw%3D680" alt=""&gt;&lt;/a&gt;Macro photo of tooth wheel mechanism with CONFIGURATION concept letters&lt;/p&gt;

&lt;p&gt;I was recently approached by someone who’s company is struggling to make a technical decision. They are a large organization who has multiple brands under a single umbrella. All of these brands make similar products at different price points and levels of quality. Let’s say they make dishwashers, just for the sake of this post.&lt;/p&gt;

&lt;p&gt;The decision this company was wrestling with was whether each of their brands should build separate iPhone apps to interface via bluetooth with their dishwashers, or if they should build one app that can be customized per brand.&lt;/p&gt;

&lt;p&gt;This post aims to show what questions a good CTO (or other tech leader) would ask, and how they would use the answers to those questions to make this decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Question 1: How Similar Are These Products Going To Be Across Brands?
&lt;/h3&gt;

&lt;p&gt;The answer to this one is not usually as simple as a single value on a scale from 1-10. The ways in which the apps are going to vary matter.&lt;/p&gt;

&lt;p&gt;Here’s some examples of variations that are easily supported by a single configurable codebase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Needing to change colors, fonts, and logos to match each brand.&lt;/li&gt;
&lt;li&gt;Needing different copy / content in various places.&lt;/li&gt;
&lt;li&gt;Excluding features from some versions of the app. For example, if the lower price point brands don’t have certain features and we want to exlude them from their apps.&lt;/li&gt;
&lt;li&gt;Needing to change the order or layout of components.&lt;/li&gt;
&lt;li&gt;Using different accounts to authenticate (brand A website accounts vs brand B website accounts)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s some examples of variations that are harder to support with a single codebase.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Needing a totally different control structure for the flow. For example, if one brand wants to use a bottom tabbar based layout and another wants to use a more custom wizard-like flow.&lt;/li&gt;
&lt;li&gt;There are wildly different legal requirements. If one want app needs to have special review from a 3rd party agency but another does not, you may not want to tangle both apps up in the regulatory restrictions.&lt;/li&gt;
&lt;li&gt;There’s simply no shared functionality at all. If that’s the case, there’s no reason to spend time building the configuration to use a single codebase.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Question 2: Are The Stake Holders For These Products Generally On The Same Page?
&lt;/h3&gt;

&lt;p&gt;By building on a single codebase, you are increasing the amount of communication and agreeance that is needed between the different brand owners.&lt;/p&gt;

&lt;p&gt;A good CTO would know to keep an eye out for binding divisions together who are unlikely to work well together over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Question 3: Are The Timelines Similar For Each Product?
&lt;/h3&gt;

&lt;p&gt;If there’s one brand that needs to get the app to market much sooner than the others, it may make sense to launch that brand as a stand alone project. You can graft on the configurable elements later to launch the other products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Question 4: What is the skill level of the team?
&lt;/h3&gt;

&lt;p&gt;It requires more engineering talent to build many apps out of one configurable project. If the team doesn’t have budget for at least a few experienced engineers to guide the development of such a system, it might be wise to build them as seperate apps.&lt;/p&gt;

&lt;p&gt;In many cases though, this would indicate the budget is simply not sufficient to set this project up for success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Making the call
&lt;/h3&gt;

&lt;p&gt;There’s significant long term value in building the apps out of a single configurable codebase. So I would say that if the answers to 2 out of 4 of those questions are indicating it should be built in that manner, it’s the right way to go.&lt;/p&gt;

&lt;p&gt;If you have less than 2 of them pointing in that direction, it’s probably worth spending some time trying to get them moving in that direction.&lt;/p&gt;

&lt;p&gt;If there’s no way that can happen, you’re best to go with individual apps. However, it should be made very clear that there are serious drawbacks to that approach over the long haul. Praticularly in maintainablity and long term efficiency.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>product</category>
      <category>leadership</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Getting into Software Sales after a decade of Engineering roles?</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Sun, 07 Apr 2019 20:54:10 +0000</pubDate>
      <link>https://forem.com/joecannatti/getting-into-software-sales-after-a-decade-of-engineering-roles-5go8</link>
      <guid>https://forem.com/joecannatti/getting-into-software-sales-after-a-decade-of-engineering-roles-5go8</guid>
      <description>&lt;p&gt;After 12 years as a software developer, I find myself considering new roles that would reduce or even eliminate my time spent writing code. One of those roles is Sales.&lt;/p&gt;

&lt;p&gt;I've spent most of my career working for SF and Valley based startups. I've been successful and have recently made my way into the upper ranks for individual contributors at some great companies.&lt;/p&gt;

&lt;p&gt;I've never worked closely with a Sales team and I know very little about what actually goes on in that world. I suspect I could be good at it based on my communication and interpersonal skills.&lt;/p&gt;

&lt;p&gt;What I would love to hear from someone who really knows that world is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can I make similar money in Sales as I do as a Senior/Principal/Staff engineer in the SF Market?&lt;/li&gt;
&lt;li&gt;What does it take to be good at sales in the software industry?&lt;/li&gt;
&lt;li&gt;How much would I need to travel?&lt;/li&gt;
&lt;li&gt;Is it best done as a full time employee of a company, or as a contractor?&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>career</category>
      <category>sales</category>
      <category>business</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Moving forward after a Code Spike</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Sat, 30 Mar 2019 16:30:55 +0000</pubDate>
      <link>https://forem.com/joecannatti/moving-forward-after-a-code-spike-2bd5</link>
      <guid>https://forem.com/joecannatti/moving-forward-after-a-code-spike-2bd5</guid>
      <description>&lt;p&gt;Writing code is often the best way to figure out what exactly needs to be done to solve a problem. In the Agile world, they call this a &lt;a href="http://agiledictionary.com/209/spike/"&gt;Spike&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A spike is when a software developer sits down and starts writing little bits of code with the goal of building a map of all the work they are going to need to eventually do to complete a project.&lt;/p&gt;

&lt;p&gt;It’s a way of quickly hacking out code that does stuff like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Querying the database to see what’s in there and how it fits together&lt;/li&gt;
&lt;li&gt;Calling 3rd party APIs to see how they work&lt;/li&gt;
&lt;li&gt;Testing the algorithm that Fred said would work in Slack to see if he’s right&lt;/li&gt;
&lt;li&gt;Anything else that might need verified before committing to a design.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spikes usually result in a bunch of messy code that kinda/sorta does most of the things that the product is going to need to do in the end. To most programmers, it feels good to do a spike. It gives more instant gratification than other methods of writing code. It makes me feel like an unstoppable force of nature, slicing through time and space, totally unaware of my colossal mediocrity. Because of that, there’s a temptation to feel that most of the work is done when the spike is done.&lt;/p&gt;

&lt;p&gt;What comes next is often the developer saying something like, “I just need to clean up the code from the spike and open a pull request”. This creates the impression that there’s not much work left to do. The bad news is that that impression is often false. The good news is that I’m going to tell you how to deal with that bad news right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s tangibly different between Spike code and Production code?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  All the edge cases. I mean all of them.
&lt;/h3&gt;

&lt;p&gt;One of the main differences between doing a spike and writing production code is what one does when an edge case becomes clear.&lt;/p&gt;

&lt;p&gt;In production code, I immediately write a test and/or alter the code to cover that scenario. In a spike, I just keep on rolling. At best, I’ll make a note to myself about it.&lt;/p&gt;

&lt;p&gt;These build up over time. Three days worth of hacking out spike code can leave a lot more of these un-handled cases in the code then you might expect.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long term maintainability
&lt;/h3&gt;

&lt;p&gt;Code written during a spike often has much less thought about maintainability put into it.&lt;/p&gt;

&lt;p&gt;Here’s an example from a spike I recently did that involved pulling all data about cohorts of students from an internal API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def cohort_ids 
  open = cohorts_api_client.search_cohorts(status: 'open', limit: 5000) 
  active = cohorts_api_client.search_cohorts(status: 'active', limit: 5000) 
  upcoming = cohorts_api_client.search_cohorts(status: 'upcoming', limit: 5000) 
  (open + active + upcoming).map(&amp;amp;:cohort_id).map(&amp;amp;:to_i).sort 
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We had significantly less than 5000 cohorts at the time. So for the purposes of my spike, setting the limit to 5000 and making one call was fine. But what would happen if we had more than 5000 cohorts with any one particular status? That code would miss them. The correct thing to do is to page through the results until there are none left.&lt;/p&gt;

&lt;p&gt;The code that actually made it into production looked like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BATCH\_SIZES = 100 

def all 
  %w(open active upcoming).map do |status| 
    fetch(status: status)
  end.inject(&amp;amp;:+).uniq 
end 

protected 

def fetch(status:, limit: BATCH\_SIZES, offset: 0) 
  batch = cohorts_api_client.search_cohorts(status: status, limit: limit, offset: offset) 
  if batch.count == limit
    batch + fetch(status: status, limit: limit, offset: offset + limit) 
  elsif batch.count &amp;lt; limit 
    batch 
  end
end

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



&lt;p&gt;That’s a pretty important refactor. It’s also exactly the type of thing that can be easily missed when a coder is rushing to get spike code into production. The spike version of the code will work fine for now. But some day in the future (probably at the worst possible moment), there will be a big influx of new cohorts and that original code would fall on its face. That would shatter the coder’s illusion of having any idea what they’re doing, not just in their work, but in their life. So lets avoid that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testability
&lt;/h3&gt;

&lt;p&gt;Spike code is typically not driven by writing tests, or the type of tests used to drive it are not the best kind for producing good designs.&lt;/p&gt;

&lt;p&gt;For the spike code listed above, I drove the development with one high level integration test. That single test ran all of the code in the spike end to end. Driving code with unit tests, which execute small portions of the code in isolation, typically leads to much better designs. This ends up being a major cause of the less-than-production-ready-ness of spike code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would the PR look like?
&lt;/h2&gt;

&lt;p&gt;Another great thing to think about is what the Pull Request is going to look like. In most cases, without some deliberate effort, it is going to be  &lt;strong&gt;way&lt;/strong&gt;  too big.&lt;/p&gt;

&lt;p&gt;I like to compare the branch with master (or develop) on Github so that I can see exactly what it would be like. That’s a good starting point for understanding that the spike code is in fact, not production ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we get out of this mess?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  1. Take relevant bits of code and put them into some sort of notes document.
&lt;/h4&gt;

&lt;p&gt;I’ll spare you a rant about how I love emacs/org-mode for this sort of thing…&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Look at each one and type up what it does, how it does it, and (most importantly) what’s not perfect about it.
&lt;/h4&gt;

&lt;p&gt;You might think you already know these things and can skip this step, but don’t!&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Create a new branch off of master (or develop or whatever) that does not include your spike code.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  4. Decide the smallest chunk of functionality that would make for a complete Pull Request
&lt;/h4&gt;

&lt;p&gt;In my most recent spike, I’m aiming to turn it into pull requests that do basically the following&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setup the credentials for accessing the APIs involved&lt;/li&gt;
&lt;li&gt;Pulled the data from the apis&lt;/li&gt;
&lt;li&gt;Setup the OO design to do the computations on that data&lt;/li&gt;
&lt;li&gt;One PR for each field that was computed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There will probably be 5 or 6 separate PRs.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Build that functionality. Reach for the code snippets in your notes from your spike as you need them.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  6. Take a special pass with each snippet you copy in to make sure all paths through the code are fully covered with unit tests and any short comings that you wrote up earlier are addressed.
&lt;/h4&gt;

&lt;p&gt;This is the most important step!&lt;/p&gt;

&lt;h4&gt;
  
  
  7. Open that PR, get feedback, make changes, merge.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  8. Go back to #3 and repeat until all the work is done
&lt;/h4&gt;

&lt;h2&gt;
  
  
  There’s an art to this…
&lt;/h2&gt;

&lt;p&gt;It’s not always going to be easy to do this. For example, Sometimes it will be really hard to break your spike into a bunch sane small PRs. Over time one develops a partly intuitive taste for what’s going to work out best. The only way to develop that taste is to try your best every time you find yourself in this situation.&lt;/p&gt;

&lt;p&gt;Good Luck!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>refactoring</category>
      <category>codequality</category>
      <category>agile</category>
    </item>
    <item>
      <title>What Biz People Need to Know About Tech: Single Page Apps</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Sat, 23 Mar 2019 17:02:10 +0000</pubDate>
      <link>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-single-page-apps-28ek</link>
      <guid>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-single-page-apps-28ek</guid>
      <description>&lt;p&gt;This is an installment in the &lt;a href="https://dev.to/joecannatti/what-biz-people-need-to-know-about-tech-series-intro-3alj-temp-slug-879578"&gt;What Biz People Need to Know About Tech&lt;/a&gt; series. It’s aim is to help non-technical business people to communicate better with engineers and provide better feedback about the value they want them to deliver.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1v6Ah4Ao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/03/book-book-pages-bookcase-415071.jpg%3Fw%3D740" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1v6Ah4Ao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://zafulabs.files.wordpress.com/2019/03/book-book-pages-bookcase-415071.jpg%3Fw%3D740" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In the 90s, calling them “Pages” made perfect sense.
&lt;/h2&gt;

&lt;p&gt;Everything used to be so simple. Here’s how web pages worked back in the day:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Type a URL into your web browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The browser reaches out to a server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The server sends you a page of specially formatted text called HTML. The HTML contains the content and a very basic definition of how it should look.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your browser renders that page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you click a link in the page, GOTO #2 (repeat until your Dad makes you sign off of AOL so he can use the telephone).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What is a “Page” in the modern web?
&lt;/h2&gt;

&lt;p&gt;At its core, the web still works that way. However, we’ve pushed the limits of what happens between steps #4 and #5 a great deal. We’ve pushed that part of the process so far that it’s started to change the mental model for the whole process.&lt;/p&gt;

&lt;p&gt;Basically, people wanted the web page to do interactive things in between when the browser rendered the page and when the user clicked another link. At first this was pretty simple stuff like making something turn bold when you hover the mouse over of it. Or maybe, letting you hide/show portions of the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  That’s the origin of JavaScript!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forumone.com/ideas/javascript-taking-over-world-and-its-got-us-too/"&gt;JavaScript is taking over the world&lt;/a&gt;. For technologists of a certain age, that’s a weird thing. This is because JavaScript was originally a &lt;a href="https://auth0.com/blog/a-brief-history-of-javascript/"&gt;quick hack added into the Netscape web browser&lt;/a&gt; to make enhancements and minor interactivity possible on a web page.&lt;/p&gt;

&lt;p&gt;It was never meant to be a programming language that entire careers, products, and empires are built upon. It was originally just a way to embed a little bit of logic into a web page.&lt;/p&gt;

&lt;h2&gt;
  
  
  A single page app is kind of like a desktop application that runs in the browser
&lt;/h2&gt;

&lt;p&gt;A single page app is essentially a web page that builds an entire user experience without ever asking the server for a new page. Basically, the first page loads an app written in Javascript. That app loads new content, sends data to the server to be saved, and does everything else that we see in modern web apps.&lt;/p&gt;

&lt;p&gt;Another way to say it is that we now build whole apps out of the little tool intended to let you make something bold when the mouse hovers over it.&lt;/p&gt;

&lt;p&gt;There was a time when this was really radical and difficult. These days though, it’s becoming totally sane and standard.&lt;/p&gt;

&lt;p&gt;It’s even becoming practical to write highly sophisticated apps like photo editors and animation tools in JavaScript and run them in the web browser. These types of products used to require building desktop applications that had to be installed and licenced on the end user’s machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where’s the business value?
&lt;/h2&gt;

&lt;p&gt;The most direct line to business value is through the enhanced level of interactivity made possible. Here’s a good question to ask yourself, “is my product and interactive application or a series of dynamically generated pages?”.&lt;/p&gt;

&lt;p&gt;For example, a product that to me seems like an obvious choice to build as a single page app is Todoist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TkkzmXp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ga1.imgix.net/screenshot/o/102437-todoist-1509095605-5117886%3Fixlib%3Drb-1.0.0%26ch%3DWidth%252CDPR%26auto%3Dformat%26fit%3Dcrop" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TkkzmXp4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ga1.imgix.net/screenshot/o/102437-todoist-1509095605-5117886%3Fixlib%3Drb-1.0.0%26ch%3DWidth%252CDPR%26auto%3Dformat%26fit%3Dcrop" alt="Image result for todoist"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The user is spending all day in the interface managing their todo list. There are many complex interactions like tagging, scheduling, commenting, ordering, etc. Every millisecond that you can shave off of the user’s experience is going to make a difference in how productive they can be.&lt;/p&gt;

&lt;p&gt;Todoist is implemented as a single page app. It also has a desktop wrapper that runs that single page app as a stand alone instance. That all makes perfect sense for the type of product that it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  When do you not want a single page app?
&lt;/h2&gt;

&lt;p&gt;If your product fits perfectly fine into the basic link-&amp;gt;page-&amp;gt;repeat model, then you’re probably better off building it that way. That pattern is simpler, cheaper, and easier to maintain than the Single Page App pattern.&lt;/p&gt;

&lt;p&gt;If you’re not going to reap any benefits from a highly interactive experience, then you want to try to avoid taking on the extra overhead of building your product as a single page application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hybrid approaches
&lt;/h2&gt;

&lt;p&gt;It’s possible to blend the link-&amp;gt;page-&amp;gt;link-&amp;gt;page approach and the SPA approach. For example, you can have a basic page model but include a user dashboard that is implemented as a SPA within the context of the other pages.&lt;/p&gt;

&lt;p&gt;In practice, this approach has some subtle drawbacks that cost you some of the benefits of a SPA, but can be a great compromise in some cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;I hope that gives you a good overview of what it means to use a Single Page App approach in building a product. With this knowledge, you should be able to engage in conversation with your technical team about whether or not this pattern is right for your company.&lt;/p&gt;

&lt;p&gt;I hope you checkout the next installment of What Business People Need to Know About Tech!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>html</category>
    </item>
    <item>
      <title>In Praise of Multiple DB setups and Rails 6</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Mon, 18 Mar 2019 13:35:02 +0000</pubDate>
      <link>https://forem.com/joecannatti/in-praise-of-multiple-db-setups-and-rails-6-1605</link>
      <guid>https://forem.com/joecannatti/in-praise-of-multiple-db-setups-and-rails-6-1605</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fzafulabs.files.wordpress.com%2F2019%2F02%2Fbandwidth-close-up-computer-1148820-1.jpg%3Fw%3D740" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fzafulabs.files.wordpress.com%2F2019%2F02%2Fbandwidth-close-up-computer-1148820-1.jpg%3Fw%3D740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like &lt;a href="https://medium.com/rubyinside/whats-coming-to-rails-6-0-8ec79eea66da" rel="noopener noreferrer"&gt;Rails 6&lt;/a&gt; is going to include first class support for configuring your app to talk to multiple databases. I’m not going to get too deep into how the feature will work in this post. I think there will be plenty of blog posts and documentation discussing that once it’s released. I want to spend some time explaining &lt;strong&gt;why&lt;/strong&gt; you’d want to access multiple databases from a single web app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read Only Connections and Follower databases
&lt;/h2&gt;

&lt;p&gt;One common use case for connecting a web applications to two databases is to have one connection to the primary read/write instance of the database and another connection to a read-only replica of the same data. This is highly useful when trying to scale a system because it allows you to move complex read queries off of the primary database.&lt;/p&gt;

&lt;p&gt;This reduces &lt;a href="https://en.wikipedia.org/wiki/Block_contention" rel="noopener noreferrer"&gt;contention&lt;/a&gt; between reads and writes and leads to better performance. If you have a background job that computes some information about your user, you can have that background job use the follower for the read queries.&lt;/p&gt;

&lt;p&gt;There will always be some level of lag between the primary db and its read-only follower, so systems have to be designed with that in mind to make this strategy usable. For example, you have to build things in such a way that it doesn’t create problems if a record has been added to the database but it hasn’t yet been copied to the read-only follower. That new record has to be able to be picked up on a subsequent run of the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  ETL, Precomputation, and Other Data Warehousing Principals
&lt;/h2&gt;

&lt;p&gt;Another set of designs that can be elagently implemented by having a web app that connects to multiple databases comes from the world of data warehousing.&lt;/p&gt;

&lt;p&gt;One of the most common designs from this family is used when complex data transformations are computed ahead of time to simplify the computation that is needed in real time.&lt;/p&gt;

&lt;p&gt;For example, imagine that we need to do a complex calculation to determine if the logged in user has a special gold status. Something like, “have they made 5 purchases in the last 60 days, written 3 product reviews, and completed 100% of their user profile”. That isn’t something that you’d want to query for on every page load.&lt;/p&gt;

&lt;p&gt;Computing that value ahead of time is a good solution to this type of problem. If you combine this with the previous suggestion of connecting to a read-only follower of the database, you can end up with a great solution where a background process reads from the read only follower, makes this complex calculation, and writes it to a database specifically used to store precomputed values. This makes it so that your primary read-write database isn’t burdened &lt;strong&gt;in anyway&lt;/strong&gt; by this relatively expensive computation.&lt;/p&gt;

&lt;p&gt;It works similarly for business analysis and reporting use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monolith -&amp;gt; Microservice Transition
&lt;/h2&gt;

&lt;p&gt;Another excellent time to consider connect your app to multiple database is when you are beginning to break a large Monolithic application up into smaller components.&lt;/p&gt;

&lt;p&gt;Let’s say for example you are planning to pull all of your user information from the main monolith into a User Microservice. One way you could approach that is to first move the data from the primary database into one that will be private to the new service. That’s going to cause you to need to refactor all the places that you are relying on database joins to the user table. That approach is no longer going to be possible once you transition to the service. You can then make a Ruby class that provides an interface to that data. This class will read the data from the new database.&lt;/p&gt;

&lt;p&gt;Then once you spin up the User Microservice, you can simply refactor that class to read from the JSON API instead of the new database. Then, you make it so that the User Microservice is the only thing that connects to the new user database.&lt;/p&gt;

&lt;p&gt;This is a very common, safe, and powerful way to evolve your architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;Rails 6 is introducing a feature that may make all of the designs discussed in this post easier to setup. It’s a great time to do some thinking about how your system could benefit from these sorts of designs.  &lt;/p&gt;

&lt;p&gt;I’d love to hear how you use multiple database setups in your systems. Comment below!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>database</category>
    </item>
    <item>
      <title>What Biz People Need to Know About Tech: Test Driven Development</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Mon, 11 Feb 2019 22:59:06 +0000</pubDate>
      <link>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-test-driven-development-37om</link>
      <guid>https://forem.com/joecannatti/what-biz-people-need-to-know-about-tech-test-driven-development-37om</guid>
      <description>&lt;p&gt;This is an installment in the &lt;a href="https://dev.to/joecannatti/what-biz-people-need-to-know-about-tech-series-intro-3alj-temp-slug-879578"&gt;What Biz People Need to Know About Tech&lt;/a&gt; series. It’s aim is to help non-technical business people to communicate better with engineers, and provide better feedback about the value they want them to deliver.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is it?
&lt;/h3&gt;

&lt;p&gt;Test driven development (commonly called “TDD”) is a technique that software developers use to get their work done. If you’ll allow me to make a music analogy, it’s like a guitar player using a pick to play a certain part as opposed to playing it fingerstyle.&lt;/p&gt;

&lt;p&gt;If you’re a golfer, it’s like using a 65° wedge instead of a regular pitching wedge to sink a chip shot.&lt;/p&gt;

&lt;p&gt;If you’re a rutabaga farmer, it’s like using nutrition blend 75 and double pruning instead of using the Barry Garbo method.&lt;/p&gt;

&lt;p&gt;Okay… That rutabaga farming one isn’t real. I have no idea how to grow a rutabaga… but you get the idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  What kind of technique?
&lt;/h3&gt;

&lt;p&gt;Writing code can be tricky because we often need to satisfy a bunch of different behaviors with the same code. For example, let’s imagine that we are writing some code that calculates the total amount a customer owes at checkout time.&lt;/p&gt;

&lt;p&gt;If you just dive in and start writing that code, it will probably go something like this&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I’ll make it sum up the price of all the items in the cart&lt;/li&gt;
&lt;li&gt;Next I’ll call the 3rd party service to calculate the tax.&lt;/li&gt;
&lt;li&gt;Then, I’ll make it so any account credit they have is deducted.&lt;/li&gt;
&lt;li&gt;Next, I’ll make it deduct the value of a coupon if the user has one.&lt;/li&gt;
&lt;li&gt;Oh wait, do they need to pay tax on the value before or after I apply the coupon?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It can be kind of like a cartoon character trying to plug leaks in a boat. Do you remember this? (I can’t find it on YouTube). A leak springs up and the character puts their finger in it to plug it. Then another pops up on the other side of the boat and they have to stretch to use their other hand to fix that one. Then they have to use their toe for the third, and so on.&lt;/p&gt;

&lt;p&gt;Sometimes you get yourself in a situation where every time you make Thing A work, you break Thing B.&lt;/p&gt;

&lt;p&gt;In our example above that would be like breaking the account credit calculation every time you make the coupon work, and then breaking the coupon when you go back and fix the account credit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TDD lets the coder specify all of the things that the code needs to do before she writes the code itself&lt;/strong&gt;. Those specifications exists forever and can be re-checked every time the code is changed.&lt;/p&gt;

&lt;p&gt;Also, in 6 months when the developer has long forgotten if the coupon value is supposed to be taken out before or after the tax is calculated, the tests are still there to make sure everything still works correctly.&lt;/p&gt;

&lt;h3&gt;
  
  
  This effects the end product
&lt;/h3&gt;

&lt;p&gt;A developer has to do things a little differently to do test driven development. It’s possible to write code that is hard or impossible to test. When a programmer is using TDD it causes the code to be designed in a different way.&lt;/p&gt;

&lt;p&gt;The ways that the design is effected by TDD are almost always positive. I’m sure there’s some obscure situation where an un-testable design would be considered better, but I can’t recall ever encountering that situation in real life.&lt;/p&gt;

&lt;p&gt;In practice, TDD improves code design.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s the value to the business?
&lt;/h3&gt;

&lt;p&gt;The value to the business comes in two flavors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Less errors and bugs in production&lt;/li&gt;
&lt;li&gt;Faster development time&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Long Term vs Short Term
&lt;/h3&gt;

&lt;p&gt;Notice above that I said TDD makes development faster. Some people will say it a bit differently. They’ll say that TDD costs more time in the short term and saves time in the long term.&lt;/p&gt;

&lt;p&gt;That’s technically true, but in my experience the balance point comes so soon that it’s more accurate to say that it’s just always faster. If the code I’m working on is going to be worked on for more than one day, I do TDD.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test First vs Test After
&lt;/h3&gt;

&lt;p&gt;Above I said that you write the specifications for the code before you write the code itself. That’s not the only way to do it, you can also write the tests afterwards and alter the code if what you started with doesn’t turn out to be easy to test.&lt;/p&gt;

&lt;p&gt;Most developers do a mix of test-first and test-after development. I’m still okay with calling that TDD, although some people will say it’s only TDD if you write the tests first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you have to do it to write good code?
&lt;/h3&gt;

&lt;p&gt;Nope. Tons of companies get by without this particular technique in their tool belt. However, it’s becoming a pretty bad sign to not have tests as a part of you code base.&lt;/p&gt;

&lt;p&gt;For the most part, once a developer learns to do test driven development well, they never go back to any other method.&lt;/p&gt;

&lt;h3&gt;
  
  
  There can be some… dogma
&lt;/h3&gt;

&lt;p&gt;Developers can get “passionate” about this stuff….&lt;/p&gt;

&lt;p&gt;I’m not sure that’s a good thing. TDD is a tool and tools are meant to help a person achieve a goal. TDD is not a goal in itself. Personally, I’m most impressed with a developer when they have laser sharp TDD skills, but understand that it’s just a way to build great stuff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developers who never learned to do it
&lt;/h3&gt;

&lt;p&gt;It takes a long time to get good at test driven development. For an experienced developer who has years of experience writing code in a different way, it can feel like trying to throw a baseball with your wrong hand.&lt;/p&gt;

&lt;p&gt;Because of this, you’ll run into people who have some pretty incorrect ideas about it. It can be good to ask someone how much TDD they have done before asking them what they think about it.&lt;/p&gt;

&lt;p&gt;As I said above, it’s very rare that someone gets the hang of it and then decides they don’t want to do it anymore.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;These days, you pretty much always want your developers to be writing tests. The tooling and learning materials have advanced to the point that it’s typically very easy to setup a test friendly development system.&lt;/p&gt;

&lt;p&gt;It helps the business by making the development team able to move faster (over the long term) and by reducing errors.&lt;/p&gt;

&lt;p&gt;It can be tricky to talk about this stuff with developers for a few reasons. They can be way too enthusiastic about it and forget that it’s just a tool. They can be defensive about it if they’ve never learned to do it. Generally, you want someone who can talk about the benefits of TDD, but doesn’t give off the vibe that it’s more important to them than the product itself.&lt;/p&gt;

&lt;p&gt;I hope this was helpful to you. I hope you come back to read the next installment of What Biz People Need to Know About Tech.&lt;/p&gt;

</description>
      <category>tdd</category>
      <category>business</category>
      <category>testing</category>
    </item>
    <item>
      <title>Refactoring Example: React  Component</title>
      <dc:creator>Joe Cannatti</dc:creator>
      <pubDate>Wed, 19 Dec 2018 19:45:54 +0000</pubDate>
      <link>https://forem.com/joecannatti/refactoring-example-react--component-1kfl</link>
      <guid>https://forem.com/joecannatti/refactoring-example-react--component-1kfl</guid>
      <description>&lt;p&gt;This post is a quick lesson, by example, of how to refactor a React component to keep business logic out of the view layer.&lt;/p&gt;

&lt;p&gt;One component of a product that I’m currently developing is a micro meditation reminder. This component allows the user to set an interval in which they want to do 3 different types of meditation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sppOfq-r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://zafulabs.files.wordpress.com/2018/12/meditation-ui.gif%3Fw%3D614" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sppOfq-r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://zafulabs.files.wordpress.com/2018/12/meditation-ui.gif%3Fw%3D614" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the interval is set, a textbox shows how long the user has until it’s time to do that meditation. When the timer reaches 0, a browser notification is displayed and the timer resets.&lt;/p&gt;

&lt;p&gt;The component is fully functional, but all of the logic about how the timer works is directly embedded in the React Component object. This is not a great design because it makes it hard to test any functionality in isolation. As such I only have one test currently. That test drives the changing of the Interval field in the DOM and asserts that the Next field updates.&lt;/p&gt;

&lt;p&gt;We are going to use TDD to refactor this component such that the timer logic no longer lives directly in the component so that we can have a sane and testable interface.&lt;/p&gt;

&lt;p&gt;Here is the code and the test we are starting with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MeditationListItem extends Component {  
  constructor(props) {
    super(props);
    this.state = {interval: 0, nextIn: "not scheduled"}
  }

  componentDidMount() {
    this.timerLoopID = setInterval(this.timerLoop.bind(this), 100);
  }

  componentWillUnmount() {
    clearInterval(this.timerLoopID);
  }

  intervalUpdated(event) {
    const interval = event.target.value;
    this.setUpTimerForInterval(interval);
    this.calculateNextIn();
  }

  setUpTimerForInterval(interval) {
    const nextAt = moment().add(interval, 'minutes');
    this.setState({ interval: interval, nextAt: nextAt });
  }

  calculateNextIn() {
    if (this.state.nextAt) {
      this.setState({nextIn: this.state.nextAt.from(moment()) });
    }
  }

  timerExpired() {
    showNotification(this.props.name);
    this.setUpTimerForInterval(this.state.interval);
  }

  timerLoop() {
    if (this.state.nextAt) {
      if (this.state.nextAt &amp;lt; moment()) {
        this.timerExpired()
      }
      else {
        this.calculateNextIn();
      }
    }
  }

  render() {
    return (
      &amp;lt;ListItem&amp;gt;
        &amp;lt;ListItemText primary={this.props.name} /&amp;gt;
        &amp;lt;TextField
          label="Interval (Min.)"
          margin="normal"
          type="number"
          defaultValue='0'
          onChange={this.intervalUpdated.bind(this)}
          className="interval-field"
        /&amp;gt;
        &amp;lt;TextField
          label="Next"
          value={this.state.nextIn}
          margin="normal"
          className="next-in"
          InputProps={{
            readOnly: true,
          }}
        /&amp;gt;
      &amp;lt;/ListItem&amp;gt;
    )
  }
}

export default MeditationListItem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first thing that jumps out to me when I think about refactoring this is that the stuff we want to remove from the React Component is the timer logic. So, I’m going to create a class called &lt;code&gt;MeditationTimer&lt;/code&gt; and use unit tests to drive the development of its interface.&lt;/p&gt;

&lt;p&gt;We know the &lt;code&gt;MeditationTimer&lt;/code&gt; class is going to need to know about the name of the meditation and the interval in which we want it to go off, so lets start with that&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MeditationTimer {
  constructor(name, interval) {
    this.name = name;
    this.interval = interval;
  }
}

export default MeditationTimer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And drive that via a test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;it('can be instantiated with name and interval', () =&amp;gt; {
  const meditationTimer = new MeditationTimer('test', 5);
  expect(meditationTimer.name).toEqual('test');
  expect(meditationTimer.interval).toEqual(5);
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What else needs to go into this new class?&lt;/p&gt;

&lt;p&gt;Well, it’s almost everything else in the React Component except for the markup!&lt;/p&gt;

&lt;p&gt;The next thing that I’m going to move is the calculation of &lt;code&gt;nextAt&lt;/code&gt; and &lt;code&gt;nextIn&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Those are the key values that makeup the state of the component.&lt;/p&gt;

&lt;p&gt;I’m going to do that in a function called &lt;code&gt;timerState()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MeditationTimer {
  constructor(name, interval) {
    this.name = name;
    this.interval = interval;
    this.nextAt = moment().add(this.interval, 'minutes');
  }

  timerState() {
    return {
      nextIn: this.nextAt.from(moment()),
      nextAt: this.nextAt,
      interval: this.interval
    };
  }
}

 describe('timerState()', () =&amp;gt; {
  let startingMoment;
  let meditationTimer;

  beforeEach(() =&amp;gt; {
    startingMoment = moment();
    meditationTimer = new MeditationTimer('test', 5);
  });

  it('sets nextAt on initialization', () =&amp;gt; {
    expect(meditationTimer.timerState().nextAt.isAfter(startingMoment)).toEqual(true);
  });

  it('sets interval on initialization', () =&amp;gt; {
    expect(meditationTimer.timerState().interval).toEqual(5);
  });

  it('calculates nextIn when called', () =&amp;gt; {
    expect(meditationTimer.timerState().nextIn).toEqual("in 5 minutes");
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Looks pretty good.&lt;/p&gt;

&lt;p&gt;Next is the timer loop itself&lt;/p&gt;

&lt;p&gt;I’ll drive that out using tests like so&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MeditationTimer {
  constructor(name, interval, callback) {
    this.name = name;
    this.interval = interval;
    this.callback = callback;
    this.setNextAt();
    this.notify = showNotification;
  }

  start() {
    return this.timerLoopID = setInterval(this.timerLoop.bind(this), 100);
  }

  stop() {
    return clearInterval(this.timerLoopID);
  }

  setInterval(interval) {
    this.interval = interval;
    this.setNextAt();
    this.callback(this.timerState());
  }

  timerState() {
    return {
      nextIn: this.nextAt.from(moment()),
      nextAt: this.nextAt,
      interval: this.interval
    };
  }

  private

  setNextAt() {
    this.nextAt = moment().add(this.interval, 'minutes');
  }

  timerExpired() {
    this.notify(this.name);
    this.setNextAt();
  }

  timerLoop() {
    if (this.interval &amp;gt; 0) {
      if (this.nextAt &amp;lt; moment()) {
        this.timerExpired();
      }
      this.callback(this.timerState());
    }
  }
}

export default MeditationTimer;

const mockCallback = jest.fn();

beforeEach(() =&amp;gt; {
  startingMoment = moment();
  meditationTimer = new MeditationTimer('test', 5, mockCallback);
});

describe('setInterval', () =&amp;gt; {
  it('updates interval and calculates nextAt', () =&amp;gt; {
    const originalNextAt = meditationTimer.timerState().nextAt;

    meditationTimer.setInterval(6);
    expect(meditationTimer.interval).toEqual(6);
    expect(meditationTimer.timerState().nextAt.isAfter(originalNextAt)).toEqual(true);
  });
});

describe('timerLoop', () =&amp;gt; {
  describe('when interval is 0', () =&amp;gt; {
    it('is a no op', () =&amp;gt; {
      meditationTimer = new MeditationTimer('test', 0, mockCallback);
      meditationTimer.timerExpired = jest.fn();
      meditationTimer.callback = jest.fn();
      meditationTimer.timerLoop();
      expect(meditationTimer.timerExpired).not.toHaveBeenCalled();
      expect(meditationTimer.callback).not.toHaveBeenCalled();
    });
  });

  describe('when interval is 1', () =&amp;gt; {
    it('calls the callback', () =&amp;gt; {
      meditationTimer = new MeditationTimer('test', 1, mockCallback);
      meditationTimer.callback = jest.fn();
      meditationTimer.timerLoop();
      expect(meditationTimer.callback).toHaveBeenCalled();
    })
  });

  describe('when timer is expired', () =&amp;gt; {
    it('resets the timer', () =&amp;gt; {
      meditationTimer = new MeditationTimer('test', 1, mockCallback);
      meditationTimer.nextAt = moment().subtract(1, 'day');
      meditationTimer.notify = jest.fn();
      const originalNextAt = meditationTimer.timerState().nextAt;
      meditationTimer.timerLoop();
      expect(meditationTimer.timerState().nextAt).not.toEqual(originalNextAt);
    })
  });
});

describe('start and stop', () =&amp;gt; {
  it('starts and clears a js interval', () =&amp;gt; {
    const timerId = meditationTimer.start();
    expect(timerId).not.toBeNaN();
    meditationTimer.stop();
  });
});
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, we have 100% test coverage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Qk_-Dbn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.us-west-2.amazonaws.com/secure.notion-static.com/a34f9413-f487-4950-b00c-b1a85d7a1a4b/Untitled.png%3FAWSAccessKeyId%3DASIAT73L2G45FFNARAXS%26Expires%3D1545334478%26Signature%3DK9CcQH4uNCTlo66wJ9631cxJyiA%253D%26x-amz-security-token%3DFQoGZXIvYXdzEEMaDJV8Ucu4HK2bUGi5HiK3A2LXiictDrUFGo6aBWZXCyMXcn4354Gn0etRxpd2nrmHStMgk1xacNvRb9qv1dNOtZeKGEKpc811cX%252Foev7Z9kbkGY5oTAee9ciUsGtGUHHwb5b5G1bJyeXyTzqN5BdvNzwBRzy5lCzdzDQv94ojBWBzQv3r0y2lWR9wD1dtCB5PAOFy0FmJ%252BAbfJDn35%252Fmk8IQXSuUZ20O7wyp5fp0tw8NNoZitDxjeuaatgkN4TM1tSI%252B7MROHCozoO1QXw4WsiKfIyeCEklYvh5FrUf2iSJx0DvkgYb8Hbos1kSw%252Bi0mUgIRCWPxwxlxl7ppgnxj%252F5r3LenqikW5icc4xhGSLgl6YdEPoGAK6tHN2mMo69DHEBZOBWBYxYCmbkNaI4XUiC12yJNPV3ofzMdRYPErGxZy9SRP3md6JX96rjCwBHAfgMNdC2p3wL8URcSo9eslTjzNdJYwOQdJ2B5AFMQsIrOeS3lbDpEZFVWckD%252BOcaWoG0bdgkkYGlVwvzaiZrOOeJCOwvnCpkFjLz6YXJ7Onp4J%252FC42mbUa253XY74cXt1TaXIDfLeO4tZBi22FaxUAJY3CGJ%252FUJW3Ao4%252Fzp4AU%253D" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Qk_-Dbn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s3.us-west-2.amazonaws.com/secure.notion-static.com/a34f9413-f487-4950-b00c-b1a85d7a1a4b/Untitled.png%3FAWSAccessKeyId%3DASIAT73L2G45FFNARAXS%26Expires%3D1545334478%26Signature%3DK9CcQH4uNCTlo66wJ9631cxJyiA%253D%26x-amz-security-token%3DFQoGZXIvYXdzEEMaDJV8Ucu4HK2bUGi5HiK3A2LXiictDrUFGo6aBWZXCyMXcn4354Gn0etRxpd2nrmHStMgk1xacNvRb9qv1dNOtZeKGEKpc811cX%252Foev7Z9kbkGY5oTAee9ciUsGtGUHHwb5b5G1bJyeXyTzqN5BdvNzwBRzy5lCzdzDQv94ojBWBzQv3r0y2lWR9wD1dtCB5PAOFy0FmJ%252BAbfJDn35%252Fmk8IQXSuUZ20O7wyp5fp0tw8NNoZitDxjeuaatgkN4TM1tSI%252B7MROHCozoO1QXw4WsiKfIyeCEklYvh5FrUf2iSJx0DvkgYb8Hbos1kSw%252Bi0mUgIRCWPxwxlxl7ppgnxj%252F5r3LenqikW5icc4xhGSLgl6YdEPoGAK6tHN2mMo69DHEBZOBWBYxYCmbkNaI4XUiC12yJNPV3ofzMdRYPErGxZy9SRP3md6JX96rjCwBHAfgMNdC2p3wL8URcSo9eslTjzNdJYwOQdJ2B5AFMQsIrOeS3lbDpEZFVWckD%252BOcaWoG0bdgkkYGlVwvzaiZrOOeJCOwvnCpkFjLz6YXJ7Onp4J%252FC42mbUa253XY74cXt1TaXIDfLeO4tZBi22FaxUAJY3CGJ%252FUJW3Ao4%252Fzp4AU%253D" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And our React Component contains nothing expect what a view should!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MeditationListItem extends Component {

  constructor(props) {
    super(props);
    this.state = {interval: 0, nextIn: "not scheduled"}
    this.timer = new MeditationTimer(this.props.name, 0, this.timerStateUpdated.bind(this));
  }

  componentDidMount() {
    this.timer.start();
  }

  componentWillUnmount() {
    this.timer.stop();
  }

  intervalUpdated(event) {
    this.timer.setInterval(event.target.value);
  }

  timerStateUpdated(timerState) {
    this.setState(timerState);
  }

  render() {
    return (
      &amp;lt;ListItem&amp;gt;
        &amp;lt;ListItemText primary={this.props.name} /&amp;gt;
        &amp;lt;TextField
          label="Interval (Min.)"
          margin="normal"
          type="number"
          defaultValue='0'
          onChange={this.intervalUpdated.bind(this)}
          className="interval-field"
        /&amp;gt;
        &amp;lt;TextField
          label="Next"
          value={this.state.nextIn}
          margin="normal"
          className="next-in"
          InputProps={{
            readOnly: true,
          }}
        /&amp;gt;
      &amp;lt;/ListItem&amp;gt;
    )
  }
}

export default MeditationListItem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>jest</category>
      <category>react</category>
      <category>refactoring</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
