<?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: Fatih</title>
    <description>The latest articles on DEV Community by Fatih (@fatihimani).</description>
    <link>https://dev.to/fatihimani</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%2F3426523%2Ff944a038-6922-4dad-ab64-7d1c4afb3c90.jpg</url>
      <title>DEV Community: Fatih</title>
      <link>https://dev.to/fatihimani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fatihimani"/>
    <language>en</language>
    <item>
      <title>A LeetCode Discussion: Coin Change Problems</title>
      <dc:creator>Fatih</dc:creator>
      <pubDate>Sat, 16 Aug 2025 16:18:30 +0000</pubDate>
      <link>https://dev.to/fatihimani/a-leetcode-discussion-coin-change-problems-2i16</link>
      <guid>https://dev.to/fatihimani/a-leetcode-discussion-coin-change-problems-2i16</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a software engineer, preparing for interviews has become more important than ever in today’s uncertain tech landscape. Among dynamic programming challenges, the coin change problems are some of the trickiest to keep a solid grip on—they seem simple at first but are easy to forget. In this article, I’ll break down these problems in a way that helps others approach them with confidence, while also reinforcing my own understanding so the logic sticks more firmly the next time I encounter them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Coin Change I Problem
&lt;/h2&gt;

&lt;p&gt;The coin change I problem asks the minimum number of coins to reach the requested amount. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money. Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1. You may assume that you have an infinite number of each kind of coin.&lt;/p&gt;

&lt;p&gt;Example 1:&lt;br&gt;
Input: coins = [1,2,5], amount = 11, Output: 3, Explanation: 11 = 5 + 5 + 1&lt;/p&gt;

&lt;p&gt;Example 2:&lt;br&gt;
Input: coins = [2], amount = 3, Output: -1&lt;/p&gt;

&lt;p&gt;Example 3:&lt;br&gt;
Input: coins = [1], amount = 0, Output: 0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While recursive solutions tend to be more intuitive, the tabulation method offers better readability - which is important to help readers understand. &lt;/p&gt;

&lt;p&gt;The idea behind the solution is to keep track of the minimum number of coins to make up all the possible remainders up to the requested amount. Intuitively, when we understand that the objective is minimization, we can set a default value of minimum number of coins for each remainder as infinity. Using python, this is as simple as using the &lt;code&gt;float('inf')&lt;/code&gt; number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;coinChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code snippet above, we can see we're initializing an array filled with the number infinity for all its members. The size of the array is intentionally set as &lt;code&gt;amount + 1&lt;/code&gt; to leave a space for the index 0 and leaving the rest of the indices idiomatic representation of the remainders. This means when we want to access the minimum number of coins for a given remainder, we can simply fetch them using the remainder number as their indices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;      &lt;span class="n"&gt;dp&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="c1"&gt;# [0, inf, inf, inf, ...]
&lt;/span&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we want to manually set the minimum number of coins to achieve 0 remainder as 0. This makes sense as the number of coins to achieve nothing is basically nothing. Hence, it is the first remainder in the array to achieve a non-infinity number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;coins&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;coin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# skip if coin is larger than the remainder
&lt;/span&gt;            &lt;span class="k"&gt;continue&lt;/span&gt;
          &lt;span class="n"&gt;candidate_min_coins&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="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="c1"&gt;# compare the previous minimum with candidate
&lt;/span&gt;          &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;candidate_min_coins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving on, we dive into the core of the solution. We can start to loop over and compute the minimum number of coins for all the possible remainders, from the smallest up until the requested amount. The logic behind the computation process involves: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;checking for each coin whether the coin is applicable for the given remainder. This means, the coin cannot be greater than the remainder otherwise it won't make up the remainder at all. &lt;/li&gt;
&lt;li&gt;revising the minimum number of coins for the given remainder if a smaller number of coins can make up the same amount. This step includes comparing the previous minimum number of coins and the new candidate.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dp&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="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dp&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ultimately, even the requested amount is treated as a remainder. For our solution to yield its answer, we can simply get the last member of the remainder minimum coins count array. However, there's still a chance that the requested amount cannot be constructed by any combination of the given coins. To handle this, we simply check whether the final answer is indeed anything smaller than infinity.&lt;/p&gt;

&lt;p&gt;The following displays the full solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;coinChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dp&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;coins&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;coin&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                  &lt;span class="c1"&gt;# skip if coin is larger than the remainder
&lt;/span&gt;                  &lt;span class="k"&gt;continue&lt;/span&gt;
                &lt;span class="n"&gt;candidate_min_coins&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="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="c1"&gt;# compare the previous minimum with candidate
&lt;/span&gt;                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;candidate_min_coins&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;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Coin Change II Problem
&lt;/h2&gt;

&lt;p&gt;The coin change II problem asks the number of ways to make up an amount using the given coins.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money. Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0. You may assume that you have an infinite number of each kind of coin. &lt;/p&gt;

&lt;p&gt;Example 1: &lt;br&gt;
Input: amount = 5, coins = [1,2,5], Output: 4&lt;br&gt;
Explanation: there are four ways to make up the amount: 5=5, 5=2+2+1, 5=2+1+1+1, 5=1+1+1+1+1&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, the idea behind the solution is to keep track of previous calculations. However, this time, we keep a record of the number of ways to make up all possible remainders. The number of ways to make up the smaller remainders determine the same for the larger ones. &lt;/p&gt;

&lt;p&gt;We start the solution by initializing default values for the number of ways to make up all possible remainders. We want to collect the highest possible number of ways to make up an amount - this indicates the direction of the number change is upwards. Therefore, the default number of ways is zero - a minimum value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&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="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="c1"&gt;# [0,0,0,0,0,...]
&lt;/span&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can initialize the number of ways to make up zero amount. There's only one way to make up the amount of zero.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;      &lt;span class="n"&gt;dp&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="c1"&gt;# [1,0,0,0,0,...]
&lt;/span&gt;      &lt;span class="c1"&gt;# ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving on, we want to iterate for every type of coin we have. For each coin, we want to assess for all possible remainder whether the coin can possibly make up each remainder. In the process, a remainder count that stays zero informs us that it cannot be made up. On the other hand, a remainder count that continuously increases by inheriting the smaller remainder counts shows that it is constructable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&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="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we need to return the number of ways to construct the requested amount. To deliver this, we can simply get the count of the last element in the array. &lt;/p&gt;

&lt;p&gt;The following shows the full solution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Solution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&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="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&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="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dp&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;coins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;coin&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dp&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;The coin change problems are dynamic programming problems with some special comparisons and operations that utilizes the previous computations.&lt;/li&gt;
&lt;li&gt;The coin change problems are more readable and easier to learn using the tabulation method.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dynamicprogramming</category>
      <category>python</category>
      <category>leetcode</category>
      <category>datastructures</category>
    </item>
    <item>
      <title>Engineering Strategies For Resolving Redis Cluster Imbalance</title>
      <dc:creator>Fatih</dc:creator>
      <pubDate>Fri, 15 Aug 2025 00:29:55 +0000</pubDate>
      <link>https://dev.to/fatihimani/engineering-strategies-for-resolving-redis-cluster-imbalance-58oo</link>
      <guid>https://dev.to/fatihimani/engineering-strategies-for-resolving-redis-cluster-imbalance-58oo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I recently recalled a feature I implemented in the past — a Redis cluster with multiple shards, serving millions of requests per day. We had extensive monitoring and alerting in place before it went live, but one risk slipped past my radar: unevenness across shards. Luckily, it never happened in production, but it could have.&lt;/p&gt;

&lt;p&gt;In this article, I’ll explain how Redis clustering works, why unevenness occurs, and the strategies I’d use to address it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redis Cache, Hash Slots, &amp;amp; Sharded Redis Cluster
&lt;/h2&gt;

&lt;p&gt;Redis is an in-memory key-value store known for its speed and support for rich data structures. To cache data, you provide a key, a value, and (usually) a TTL (time-to-live) so that expired entries are automatically removed.&lt;/p&gt;

&lt;p&gt;In a single-instance Redis setup, all hash slots (0–16383) are allocated to the same server. In a sharded Redis cluster, a key’s hash slot is calculated as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;CRC16&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nt"&gt;key&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;%&lt;/span&gt; &lt;span class="nt"&gt;16384&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each shard in the cluster owns a range of hash slots. When you store or fetch a key, Redis determines its hash slot, then routes the request to the shard responsible for that range.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Threats of An Uneven Redis Cluster
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Hot Shard Performance Bottlenecks: Disproportionate traffic on certain shards can cause performance bottlenecks. This can lead to serious CPU or memory max-out occurrences and latency issues.&lt;/li&gt;
&lt;li&gt;Premature key evictions: This can happen to shards nearing their maximum memory capacity. Based on its &lt;code&gt;maxmemory-policy&lt;/code&gt; configuration, Redis will prioritize new entries and remove older qualified keys on such shards prematurely. A Primary data source layer can be severely impacted when said Redis cluster serves as caching layers.&lt;/li&gt;
&lt;li&gt;Replication Traffic and Failover Issues: High traffic on hot shards will cause high replication traffic as well. Unmanageable replication tasks can lead to replication lag, leaving the replicas too far behind the master. In failover situations where a lagging replica gets promoted to master, a 'behind' master instance will cause cache reads to return stale results.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Shards Become Uneven
&lt;/h2&gt;

&lt;p&gt;Uneven load across shards can happen for many reasons. Here are the most common:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TTL Skew:
Some keys live longer than others. If certain keys have much longer TTLs, their shards may accumulate more data over time, leading to memory imbalance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xpnl0eva1fwqy99t4vc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2xpnl0eva1fwqy99t4vc.png" alt="TTLSkew" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slot Bias:
Engineers often format cache keys predictably (e.g., user:12345), so the same parts of the key end up influencing the hash slot calculation. Without randomness, traffic can cluster around specific slot ranges.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5svpfjvrq1b3u1wjilx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5svpfjvrq1b3u1wjilx.png" alt="SlotBias" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hot Keys:
Even with a fair key distribution, some keys get far more traffic. For example, if a certain range of user IDs is more active, those keys can overwhelm the shard(s) that store them, causing CPU and memory hotspots.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewe1j80e7djbp1ciiyso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewe1j80e7djbp1ciiyso.png" alt="HotKeys" width="717" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions
&lt;/h2&gt;

&lt;p&gt;While there are a number of different workarounds to these issues, it's important as a software engineer to know some of the more common ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Isolation
&lt;/h3&gt;

&lt;p&gt;Should certain key formats require extended life, it might be better to propose hosting a dedicated cluster to isolate its effects. Separating them can help engineers predict the peaks and slopes of the Redis cluster performance metrics. It can be challenging to monitor a cluster filled with key-value pairs that behave differently all the time. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdbsx5zq2fte4h08388z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdbsx5zq2fte4h08388z.png" alt="IsolationTTLVariation" width="800" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can implement the same behavior separation for Hot Key issues. A whole cluster dedicated for them will allow engineers to allocate a fine-tuned replica count or larger compute instances to overcome its traffic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomzxeh7du3awwafuqfn8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomzxeh7du3awwafuqfn8.png" alt="IsolationHotKeys" width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, it's important to keep note that the isolation strategy can increase management overhead as you would have to think about scaling and monitoring more than one cluster. More often than not, the scale-out multiplier is not similar between clusters. This is because the growth of data for each cluster is not the same. Hence, engineers will have to continuously monitor the resulting behavior in production to make sure the scale-out for each cluster has stabilized in a safe position.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Sharding
&lt;/h3&gt;

&lt;p&gt;Rather than spinning up a separate cluster, identifiable hot keys can be put through an additional hashing function that helps distribute hot keys to other hash slots. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8z2o99xu0zmuubveren.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8z2o99xu0zmuubveren.png" alt="KeySharding" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Standardization
&lt;/h3&gt;

&lt;p&gt;Sometimes, different TTLs can be unintentional. Therefore, setting a uniform TTL for all keys might be a feasible option.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix Bad Hashing
&lt;/h3&gt;

&lt;p&gt;Avoiding the usage of sequential IDs like integer entity IDs can help reduce over-grouping. The hash of the final Redis keys might end up located in neighboring hash slot results.&lt;/p&gt;

&lt;p&gt;The Redis' key hash tagging feature lets you tell Redis to consider a special part of the key to determine which hash slot it should fall into. This unlocks the possibility of choosing a deterministic hash function to tune your shard selection. &lt;/p&gt;

&lt;p&gt;Tips for what goes inside the curly braces (hash tag):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If your primary entity ID seem to be random enough (UUIDs, hashes, etc.), placing it inside hash tag can get you a pretty good distribution. &lt;/li&gt;
&lt;li&gt;For sequential IDs like integers, it might be worth hashing before placing it inside the curly braces.&lt;/li&gt;
&lt;li&gt;Low cardinality values, a field that has very few distinct values, can skew your Redis load across shards even further as it results in small number of hash slots. Therefore, it is important for engineers to analyze the range of possible values before deciding what goes into the hash tag. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Optionally, you can test your key design and simulate the cache data evenness across shards before you release it to production.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resharding
&lt;/h3&gt;

&lt;p&gt;As a short-term fix, adding shards partitions the hash slot space into smaller ranges, which can temporarily spread the load more evenly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4uf6z0v7epse9ltovsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4uf6z0v7epse9ltovsb.png" alt="Resharding" width="800" height="746"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, if the underlying cause of imbalance remains—such as bad key hashing or hot keys—the skew will eventually reappear. If the newly split hash slot ranges don’t accurately isolate the hot keys, the imbalance in GET/SET operations will simply shift from one shard to another. In cases where the root problem is bad hashing, resharding only becomes an effective remedy after reaching very high shard counts—an approach that wastes resources by assigning many shards to underutilized hash slot ranges, reducing cost efficiency.&lt;/p&gt;

&lt;p&gt;Resharding also carries significant operational overhead. During shard addition, Redis migrates keys between shards, which can consume bandwidth and CPU, leading to latency spikes that may exceed acceptable SLAs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A Redis Cluster imbalance is a serious threat to many aspects of a system. &lt;/li&gt;
&lt;li&gt;It can take different forms.&lt;/li&gt;
&lt;li&gt;It can be addressed using various strategies, depending on the underlying cause.&lt;/li&gt;
&lt;li&gt;Some strategies provide a temporary remedy, while others seeks to tackle the root cause permanently.&lt;/li&gt;
&lt;li&gt;Each approach has its own benefits and trade-offs, so it’s important to assess urgency, ongoing maintenance needs, and cost implications.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redis</category>
      <category>distributedsystems</category>
      <category>systemdesign</category>
      <category>backend</category>
    </item>
    <item>
      <title>Problem Solving Tools for Software Engineers</title>
      <dc:creator>Fatih</dc:creator>
      <pubDate>Mon, 11 Aug 2025 11:58:54 +0000</pubDate>
      <link>https://dev.to/fatihimani/problem-solving-tools-for-software-engineers-2552</link>
      <guid>https://dev.to/fatihimani/problem-solving-tools-for-software-engineers-2552</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a software engineer, I solve problems constantly. Looking back, I realize that at their core, software engineers are essentially thinking machines. Our daily routine closely resembles that of professional business consultants: we ask questions, gather data, validate our understanding, identify the root problem, and explore possible solutions. &lt;/p&gt;

&lt;p&gt;Larger companies typically handle significantly more traffic than smaller ones, which means their backend systems operate at a much greater scale. In addition, bigger businesses tend to have more teams, bringing more people into the mix. With increased manpower and more complex systems, it's safe to say: the bigger the company you work for, the more challenges you're likely to encounter.&lt;/p&gt;

&lt;p&gt;I've made my fair share of mistakes throughout my career. I frequently struggled with issues like logical inconsistency and inaccurate solutions in my thinking. As I transitioned to larger companies, these challenges began to affect both my speed and performance. Fast forward to today—now a more experienced engineer—I’ve found myself returning to the fundamentals and renewing my trust in the logical tools and thinking frameworks I once learned. More often than not, they've helped me deliver beyond expectations. Through this article, I hope to help readers reconnect with those same foundations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Entity Relationship Diagram
&lt;/h2&gt;

&lt;p&gt;Also known as ERD, the Entity-Relationship Diagram is often underestimated by engineers as a communication tool—at least in my experience over the past four years. While it may work reasonably well for communicating with other engineers, non-technical stakeholders are often left in the dark. When the message isn’t clear or memorable, they end up asking the same questions repeatedly down the line. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxg36t7ej87vmkk6t29ci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxg36t7ej87vmkk6t29ci.png" alt="A Sample ERD" width="749" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my experience, ERDs aren't limited to database design. Even when entities aren't directly related, an ERD can still be useful—it helps abstract away the underlying complexity and clarify their relationships. Many data analysts often misinterpret the data they work with simply because they’re unaware of how downstream entities are connected. &lt;/p&gt;

&lt;p&gt;In some cases, even class object relationships can be visualized using ERD-like diagrams, although UML is the more standard approach for this purpose. Clearly representing these relationships adds transparency to backend systems and makes them easier to reason about.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdy94hiwsemkp56pnjvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwdy94hiwsemkp56pnjvx.png" alt="A Sample Conceptual ERD" width="669" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When communicating with non-technical stakeholders, a full-blown ERD can be overwhelming. To make things more accessible, we can simplify it into a conceptual ERD instead. Conceptual ERDs typically omit internal fields, allowing readers to focus more clearly on the entities themselves and the relationships between them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sequence Diagram
&lt;/h2&gt;

&lt;p&gt;In many engineering teams, you’ll see one “mega diagram” that tries to do everything — show infrastructure, endpoints, databases, and the step-by-step flow of a process. This is very common when engineers gather and sketch up a rough system design proposition. While it’s technically possible, in practice it often ends up looking like an overstuffed subway map. They are hard to read, harder to maintain, and usually outdated within a few sprints.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6frtt02sn8j7xgnahkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk6frtt02sn8j7xgnahkf.png" alt="Messy Drafts" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In reality, architecture diagrams and sequence diagrams serve different purposes. Keeping them separate not only makes them clearer but also makes the documentation far more useful in the long run. &lt;/p&gt;

&lt;p&gt;To put simply, an architecture diagram shows the layout of your system. They highlight resources and components, help distinguish public and private boundaries, as well as show all the supporting middlewares. This view helps engineers estimate the effort and resources needed for a change or integration. The main purpose of the diagram is to highlight where things live and how they connect — not about how they behave over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt5lce9gj12egkddney0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyt5lce9gj12egkddney0.png" alt="A Sample Architecture Diagram" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A sequence diagram shows how a process happens. They highlight the actors or services involved as well as the messages exchanged in a chronological order. Rather than having to bring the entire infrastructure into focus, a sequence diagram only displays relevant actors and services involved in a certain due process.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j3zsbgmwg149wedor8i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3j3zsbgmwg149wedor8i.png" alt="A Sample Sequence Diagram" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you try to capture both system structure and process behavior in the same diagram, the result is usually so unreadable that it does neither of the jobs well. Separating them gives you the best of both worlds: a clean high-level architecture view for planning and integration work and a focused step-by-step sequence view for understanding specific flows. This separation keeps each diagram lightweight, relevant, and easy to update. When you or your teammates revisit the documentation months later, it’s easy enough to recognize. The small extra effort up front pays for itself many times over in clarity and maintainability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nodal Analysis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7pgmfu5chlqvgun3qun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq7pgmfu5chlqvgun3qun.png" alt="Kirchoff's Law" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In electrical engineering, Kirchhoff’s Current Law (KCL) states that the total current entering a node must equal the total current leaving it. This principle ensures that no energy is mysteriously created or lost in a circuit—it all flows in balance. Interestingly, this idea has a valuable parallel in software engineering, especially when it comes to observability and system monitoring. &lt;/p&gt;

&lt;p&gt;Think of a node in an electrical circuit as a service, endpoint, or processing unit in your architecture. Requests, events, or messages flow into it, and outcomes flow out. These outcomes can be categorized as successful responses, failures, timeouts, or even dropped requests. If we want reliable metrics and trustworthy dashboards, we must account for all inputs and outputs at the same observation point, just like how an electrical engineer analyzes a circuit node. &lt;/p&gt;

&lt;p&gt;Too often in software systems, teams monitor “success rate” without fully accounting for what flows in and out of the system. Maybe successful responses are logged at the application layer, but errors are only visible at the proxy level. Or incoming requests are counted at the edge service, while failures are logged deeper in the stack. These mismatches in observation scope make metrics unreliable and can mislead you about the health of your system. &lt;/p&gt;

&lt;p&gt;By borrowing from KCL, we can enforce a clean accounting model: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Total Inputs = Successful Outputs + Failed Outputs + Any Other Exit States&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This mindset forces rigor. If you see 10,000 requests coming into a node, but only 9,500 accounted for in your success and failure metrics, something is wrong. Are 500 being dropped silently? Are retries being double-counted upstream? Are metrics being sampled inconsistently? Just like charge can’t pile up in a circuit, requests shouldn’t “disappear” in a system. Applying this “sum in = sum out” framework helps engineers spot blind spots in their observability stack and encourages consistent monitoring instrumentation across distributed systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow Chart Diagram
&lt;/h2&gt;

&lt;p&gt;If you mostly work on high-level designs, you might not use flowcharts very often. In many projects, they’re even skipped entirely, especially when the code implementation seems self-explanatory.&lt;/p&gt;

&lt;p&gt;However, when you need to explain and document complex logic with multiple conditions, a flowchart is often the best tool for the job. Compared to architecture and sequence diagrams, it’s far better at showing branching paths, loops, and step-by-step tasks. Flowcharts are commonly used to illustrate low-level algorithms or detailed workflows, where an engineer can dive into specifics — such as exactly how many tasks are involved to complete a process. This level of detail makes it easier to communicate complex logic clearly to a wide range of audiences.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fp4wbema8b4oi7m6cqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5fp4wbema8b4oi7m6cqr.png" alt="A Sample Flow Chart" width="731" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Gantt Chart
&lt;/h2&gt;

&lt;p&gt;It’s commonly used by project managers to identify critical paths and estimate timelines for key milestones. Usually displayed as a directed graph, it serves as an effective visualization tool for displaying the number of tasks, their relative difficulty, and the dependencies between them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d8v265hk98bkdhgd1r9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7d8v265hk98bkdhgd1r9.png" alt="A Sample Gantt Chart" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For software engineers, this kind of visualization can be especially helpful. For example, when planning a project, you can estimate a realistic completion date by breaking your sprint into clear checkpoints and subtasks. Mapping these out helps you identify dependencies and allocate time more effectively.&lt;/p&gt;

&lt;p&gt;The Gantt chart can also be great for simpler use cases. For instance, when working on a project that involves multiple parties, it’s easy to lose track of who’s responsible for what, leading to wasted productive time. A Gantt chart helps your team by showing the dependencies between subtasks, allowing everyone involved to focus their energy on actionable items in parallel—rather than waiting or getting lost in the process. And to make it effective, you don’t even need to define a minimum or maximum time estimates for each subtask if what you’re trying to achieve is just parallelism and not time estimation.&lt;/p&gt;

&lt;h2&gt;
  
  
  SWOT Framework
&lt;/h2&gt;

&lt;p&gt;The SWOT Framework is a popular method usually used to assess an individual, a team, or a company's competitive position and to plan a strategy for growth. The name stands for the 4 aspects that the framework covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Strength: These are positive attributes internal towards the subject. They can be efficient task handling, skilled work force, or high brand reputation.&lt;/li&gt;
&lt;li&gt;Weakness: These are negative aspects or limitations that can hinder the subject from growth. This includes poor customer care, slow response, and lack of discipline.&lt;/li&gt;
&lt;li&gt;Opportunities: These are external factors that can be leveraged for growth. &lt;/li&gt;
&lt;li&gt;Threats: These are external factors unfavorable to the subject's progress.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26p2i2s1w1lm9yv7fu6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26p2i2s1w1lm9yv7fu6p.png" alt="A Sample SWOT" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ironically, the framework’s popularity sometimes works against it — people overlook it or treat it as a routine checkbox exercise. In reality, it’s one of the most valuable tools for activities like sprint reviews or team retrospectives. From personal experience, filling out a SWOT grid on the spot can be surprisingly challenging; when past challenges or successes aren’t fresh in mind, engineers often struggle to recall key lessons learned or what went particularly well. It can be far more effective if the SWOT form is available to fill out at any time during the week or sprint, so when incidents occur, team members can capture them while the details are still fresh. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;As a problem solver, you don’t have to reinvent the wheel by coming up new ways to break down a problem or display information. &lt;/li&gt;
&lt;li&gt;Existing frameworks can help us move faster when used for the right purpose properly.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>problemsolving</category>
      <category>behavioural</category>
      <category>technology</category>
      <category>team</category>
    </item>
    <item>
      <title>A Guide to Dynamic Programming</title>
      <dc:creator>Fatih</dc:creator>
      <pubDate>Mon, 11 Aug 2025 08:37:07 +0000</pubDate>
      <link>https://dev.to/fatihimani/a-guide-to-dynamic-programming-kne</link>
      <guid>https://dev.to/fatihimani/a-guide-to-dynamic-programming-kne</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;For a software engineer, cracking interview problems is essential. The number of new problems coming out each year makes it challenging. However, it’s the dynamic programming problems that I despise the most - the type I struggle with. They say, teaching others what you learned help master it even more. This article will reiterate what dynamic programming is about and the common strategies to identify and solve them. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is DP?
&lt;/h2&gt;

&lt;p&gt;Dynamic programming is a technique, that solves problems by breaking them into smaller and more manageable pieces. These subproblems usually share similar structures, allowing a common solution pattern to be applied repeatedly to build the solution for the entire problem.&lt;/p&gt;

&lt;p&gt;All dynamic programming problems can be solved using recursion because they can be broken down into smaller tasks that share a similar logic. A typical recursive function includes a base case—a logic that’s usually placed at the top of the function and checks a condition to determine when to stop. The base case acts as the termination point for the recursive call stack, ensuring the function eventually returns a result rather than letting it run an infinite loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# base case
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# recursion calls
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, some problems can be further optimized using memoization, which is essentially a form of caching. Instead of repeatedly performing the same recursive calls, we store the results of those calls in a cache. Then, if a recursive call needs a value we’ve already computed, we can simply return the cached result. &lt;/p&gt;

&lt;p&gt;Memoization significantly improves runtime efficiency by avoiding redundant computations. It can also reduce the depth of the recursive call stack in some problems, helping to avoid issues like Python’s default maximum recursion depth of around 1000. However, memoization doesn’t completely eliminate recursion limits if the problem itself requires very deep recursive calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="o"&gt;=&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# base case
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# memoization check
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# populate memo
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tabulation: A Bottom-up Approach
&lt;/h2&gt;

&lt;p&gt;The top-down approach to dynamic programming, using recursion and memoization, often feels more intuitive to write and understand. However, in some problems, the bottom-up tabulation method can be significantly faster because it avoids the overhead of recursive calls and handles the subproblems more efficiently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="n"&gt;fb&lt;/span&gt; &lt;span class="o"&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="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fb&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fb&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical tabulation approach involves creating a DP table, often implemented as an array, to store the results of previously solved subproblems—which, in a way, acts similarly to memoization. Unlike the top-down method, tabulation relies on loops rather than recursive calls to fill in this table and build the solution from smaller subproblems upward.&lt;/p&gt;

&lt;p&gt;Although every dynamic programming problem can be solved using either top-down or bottom-up techniques, recursion comes with practical limits, such as the maximum call stack depth, which can make top-down solutions unsuitable for problems requiring very deep recursion. Bottom-up tabulation avoids these issues by relying on loops rather than recursion, making it applicable to all DP problems. Still, there are cases where the top-down approach remains more efficient, especially when the DP state space is large and sparse, since it avoids computing unnecessary states.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recognizing Dynamic Programming Problems
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Dynamic programming problems usually have optimal substructure, meaning the solution to the overall problem can be built from solutions to smaller subproblems. If you can describe your problem as “my answer depends on smaller answers,” it’s often a DP problem. For example, the shortest path to a cell in a grid depends on the shortest paths to the neighboring cells.&lt;/li&gt;
&lt;li&gt;Another key sign of DP is overlapping subproblems. This happens when the same smaller problems keep coming up repeatedly in different parts of your solution. A classic example is the naive recursive Fibonacci, where &lt;code&gt;fib(n-1)&lt;/code&gt; and &lt;code&gt;fib(n-2)&lt;/code&gt; get recomputed many times. DP avoids this by storing results to prevent redundant calculations. &lt;/li&gt;
&lt;li&gt;Many DP problems involve making choices at each step, like deciding whether to include or exclude an item, or choosing one path over another. For instance, in the Knapsack problem, you choose whether to add an item or leave it out. These decisions create different subproblems that DP can solve efficiently. &lt;/li&gt;
&lt;li&gt;Problems that ask you to find the minimum, maximum, longest, shortest, cheapest, or number of ways to do something often indicate DP. For example, finding the minimum cost to climb stairs or counting the number of unique paths in a grid both fall under DP because they involve accumulating or comparing results across subproblems.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Dynamic programming (DP) is a powerful problem-solving technique used to efficiently solve problems that can be broken into overlapping subproblems with optimal substructure. Instead of solving the same subproblems repeatedly, DP stores intermediate results either through recursion with memoization (top-down) or by filling in a table iteratively (bottom-up tabulation). Many DP problems involve finding the best, minimum, maximum, or counting the number of ways to achieve something. Recognizing DP problems often comes down to spotting repeated work, decision-making at each step, and defining states that capture the essence of subproblems. Although the top-down approach is often more intuitive, bottom-up solutions can avoid issues like stack overflows and may run faster in certain cases. Overall, DP is essential for tackling many complex problems efficiently, especially in coding interviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.geeksforgeeks.org/competitive-programming/dynamic-programming/" rel="noopener noreferrer"&gt;GeeksForGeeks: DP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.spiceworks.com/tech/devops/articles/what-is-dynamic-programming/" rel="noopener noreferrer"&gt;SpiceWorks - What is DP&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>dsa</category>
      <category>leetcode</category>
      <category>programming</category>
    </item>
    <item>
      <title>Decorator Patterns in Go</title>
      <dc:creator>Fatih</dc:creator>
      <pubDate>Mon, 11 Aug 2025 08:14:55 +0000</pubDate>
      <link>https://dev.to/fatihimani/decorator-patterns-in-go-110b</link>
      <guid>https://dev.to/fatihimani/decorator-patterns-in-go-110b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The decorator pattern is a software design pattern that lets you add additional functionality on top of existing logic. The first thing that comes to people’s minds to tackle this is using inheritance — which makes complete sense. However, inheritance is inherently static. If you have multiple variations of additional functionality, or worse, various combinations of them, you would then have to create all the possible combinations as separate classes that extend the base class. In these cases, your codebase quickly grows in size and becomes less maintainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Decorator Pattern
&lt;/h2&gt;

&lt;p&gt;Implementing the decorator pattern requires the base logic you want to extend to implement a base interface — a single contract that defines what methods it provides and what they produce. You can then create classes that implement this interface while containing another internal object that also implements the same interface. The logic inside the interface methods you override can reuse the implementation of the internal object while adding additional behavior — or even ignore the base logic completely if desired. Moreover, it’s entirely possible to wrap any class that already has extended logic, allowing the decorator to add even more functionality on top of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCream&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Vanilla IceCream"&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 say, Ben and Mike each wants acustom configuration of their ice cream, Ben prefers Vanilla ice cream with Chocolate Frostings on top of them while Mike prefers Vanilla ice cream with Chocolate Frostings &amp;amp; Caramel Sauce (not even sure if that’s a thing). The inheritance way of solving this would be to create an entirely new class that satisfies the combination required. Hence, the additional classes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCreamWithChocolateFrostings&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;VanillaIc&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCreamWithChocolateFrostings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VanillaIc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with Chocolate Frostings"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCreamWithChocolateFrostingsWithCaramelSauce&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;VanillaIcWithChoco&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCreamWithChocolateFrostings&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCreamWithChocolateFrostingsWithCaramelSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VanillaIcWithChoco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with Chocolate Frostings and Caramel Sauce"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, another person, John, joins them and wants a Vanilla ice cream with only Caramel Sauce.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCreamWithCaramelSauce&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;VanillaIc&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCreamWithCaramelSauce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;VanillaIcWithChoco&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with caramel sauce"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, think about even more toppings you could add and follow the same approach we’ve used so far. You can already imagine how large the codebase will become if this continues. With the decorator pattern, you simply define an interface—one that returns the actual flavors of the ice cream class implementation—and let your decorator classes adhere to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;IIceCream&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;VanillaIceCream&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Vanilla IceCream"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ChocolateFrostingDecorator&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IceCream&lt;/span&gt; &lt;span class="n"&gt;IIceCream&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ChocolateFrostingDecorator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with Chocolate Frosting"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IceCream&lt;/span&gt; &lt;span class="n"&gt;IIceCream&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" with Caramel Sauce"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamOne&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamOneWithChocolateFrosting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ChocolateFrostingDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamOne&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamOneWithChocolateFrostingWithCaramelSauce&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamOneWithChocolateFrosting&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iceCream1: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;iceCreamOneWithChocolateFrostingWithCaramelSauce&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;iceCreamTwo&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamTwoWithChocoFrosting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ChocolateFrostingDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamTwo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamTwoWithChocoFrWithCaramelSauce&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamTwoWithChocoFrosting&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iceCream2: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;iceCreamTwoWithChocoFrWithCaramelSauce&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;iceCreamThree&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;VanillaIceCream&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamThreeWithCaramelFrostingOnly&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamThree&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iceCream3: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;iceCreamThreeWithCaramelFrostingOnly&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&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;In the event that someone else wants the same customizations but on a banana ice cream instead, as long as the Banana IceCream class implements the base interface, the existing decorators will work on them just fine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;BananaIceCream&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;BananaIceCream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetIceCream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Banana IceCream"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// ...&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;

    &lt;span class="n"&gt;iceCreamFour&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;BananaIceCream&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;iceCreamFourWithCaramelSauceOnly&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;CaramelSauceDecorator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IceCream&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iceCreamFour&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"iceCream4: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;iceCreamFourWithCaramelSauceOnly&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetIceCream&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 increase the complexity of the problem and consider a case where the existing flavors need to be stacked in a different order. With inheritance, you would end up doubling or even tripling the amount of existing code. The decorator pattern enables solutions such as accepting a stack of flavors and looping through each of them—perhaps recursively—and applying the appropriate decorator using a switch-case statement at each step.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Exploring design patterns can be a good thing to avoid common pitfalls of writing large scale projects.&lt;/li&gt;
&lt;li&gt;Decorator patterns help you stack additional logic on top of existing code in a more maintainable way.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://refactoring.guru/design-patterns/decorator" rel="noopener noreferrer"&gt;Decorator Pattern by Refactoring Guru&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>go</category>
      <category>designpatterns</category>
    </item>
  </channel>
</rss>
