<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	
	>
<channel>
	<title>
	Comments on: How to Make If Statements More Understandable	</title>
	<atom:link href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/</link>
	<description>Jonathan Boccara&#039;s blog</description>
	<lastBuildDate>Mon, 17 Aug 2020 14:50:40 +0000</lastBuildDate>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.3</generator>
	<item>
		<title>
		By: Jerry Coffin		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-442</link>

		<dc:creator><![CDATA[Jerry Coffin]]></dc:creator>
		<pubDate>Tue, 25 Jul 2017 17:37:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-442</guid>

					<description><![CDATA[At least in the case of your online store example, it seems to me that you&#039;re attempting a tactical correction to a strategic problem. The strategic problem is that despite a name that immediately sounds like it has only one responsibility, `applyDiscount` really does a number of separate things. It figures out which of a number of possible discounts to apply to a product, then it applies the chosen one.

What we should have is a top-level business rule that says something to the effect that we&#039;re going to give the customer the best price currently available on their order. To do this, we want something like this:

std::vector possible_prices;

possible_prices.push_back(base_price);

for (auto const &#038;discount : current_discounts) 
    if (discount.applies_to(order))
        possible_prices.push_back(discount(order));

Price discounted_price = *std::min_element(possible_prices.begin(), possible_prices.end());

Price final_price = std::max(discounted_price, item.minimum_price);

Then, each `applies_to` only has to deal with *one* question: does this discount apply to this particular order? So, for your case of a sale that applies solely to online-only items, it would just be:

bool applies_to(Order order) { 
    return isSoldOnlineOnly(order.item);
}

Likewise for the red-tag, and so on.

This has substantial advantages beyond mere readability of the code. It also means that we&#039;ve de-coupled the code for the individual discounts. When the sales manager decides to add some new discount, we define one new discount, and add it to `current_discounts`. When some sale ends, we remove it from `current_discounts`. Our overall logic is unaffected by the details of an individual discount.

This de-coupling also means that the code for any one discount is generally quite trivial--we have a business rule that relates to when one specific discount applies, and we embody that rule, by itself, in our code. Somebody who wants to modify the online-only sale doesn&#039;t need to even see the code for the red-tag sale, not to mention figuring out how to fit in his change without affecting the other discounts.

Now, it may be that this doesn&#039;t apply to the original code you were looking at (hard to guess since I&#039;ve never seen it, and don&#039;t eve have a clue of what sort of situation it&#039;s dealing with). It is, however, my experience that if you&#039;re running into the basic problem of complex and/or deeply nested `if` statements, you usually have a fundamental design problem. Expressing those complex conditions more clearly is obviously good, but it&#039;s clearly a lot better to correct the design to eliminate the problem entirely (and that&#039;s possible not only in this case, but in my experience in most others as well).]]></description>
			<content:encoded><![CDATA[<p>At least in the case of your online store example, it seems to me that you&#8217;re attempting a tactical correction to a strategic problem. The strategic problem is that despite a name that immediately sounds like it has only one responsibility, `applyDiscount` really does a number of separate things. It figures out which of a number of possible discounts to apply to a product, then it applies the chosen one.</p>
<p>What we should have is a top-level business rule that says something to the effect that we&#8217;re going to give the customer the best price currently available on their order. To do this, we want something like this:</p>
<p>std::vector possible_prices;</p>
<p>possible_prices.push_back(base_price);</p>
<p>for (auto const &amp;discount : current_discounts)<br />
    if (discount.applies_to(order))<br />
        possible_prices.push_back(discount(order));</p>
<p>Price discounted_price = *std::min_element(possible_prices.begin(), possible_prices.end());</p>
<p>Price final_price = std::max(discounted_price, item.minimum_price);</p>
<p>Then, each `applies_to` only has to deal with *one* question: does this discount apply to this particular order? So, for your case of a sale that applies solely to online-only items, it would just be:</p>
<p>bool applies_to(Order order) {<br />
    return isSoldOnlineOnly(order.item);<br />
}</p>
<p>Likewise for the red-tag, and so on.</p>
<p>This has substantial advantages beyond mere readability of the code. It also means that we&#8217;ve de-coupled the code for the individual discounts. When the sales manager decides to add some new discount, we define one new discount, and add it to `current_discounts`. When some sale ends, we remove it from `current_discounts`. Our overall logic is unaffected by the details of an individual discount.</p>
<p>This de-coupling also means that the code for any one discount is generally quite trivial&#8211;we have a business rule that relates to when one specific discount applies, and we embody that rule, by itself, in our code. Somebody who wants to modify the online-only sale doesn&#8217;t need to even see the code for the red-tag sale, not to mention figuring out how to fit in his change without affecting the other discounts.</p>
<p>Now, it may be that this doesn&#8217;t apply to the original code you were looking at (hard to guess since I&#8217;ve never seen it, and don&#8217;t eve have a clue of what sort of situation it&#8217;s dealing with). It is, however, my experience that if you&#8217;re running into the basic problem of complex and/or deeply nested `if` statements, you usually have a fundamental design problem. Expressing those complex conditions more clearly is obviously good, but it&#8217;s clearly a lot better to correct the design to eliminate the problem entirely (and that&#8217;s possible not only in this case, but in my experience in most others as well).</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Vladislav Kaplan		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-438</link>

		<dc:creator><![CDATA[Vladislav Kaplan]]></dc:creator>
		<pubDate>Tue, 25 Jul 2017 10:02:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-438</guid>

					<description><![CDATA[Thank you for the article.]]></description>
			<content:encoded><![CDATA[<p>Thank you for the article.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Giannis Vrentzos		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-433</link>

		<dc:creator><![CDATA[Giannis Vrentzos]]></dc:creator>
		<pubDate>Sun, 23 Jul 2017 10:28:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-433</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-431&quot;&gt;Ryan Phelps&lt;/a&gt;.

I agree about the negation when an &quot;if&quot; is followed by an &quot;else&quot; clause.
In my opinion, the code is more readable without the blank return statement. For example:

&lt;pre&gt;&lt;code&gt;
if(isSoldOnlineOnly()) {

} else {

}
&lt;/pre&gt;&lt;/code&gt;]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-431">Ryan Phelps</a>.</p>
<p>I agree about the negation when an &#8220;if&#8221; is followed by an &#8220;else&#8221; clause.<br />
In my opinion, the code is more readable without the blank return statement. For example:</p>
<pre><code>
if(isSoldOnlineOnly()) {

} else {

}
</code></pre>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Jonathan Boccara		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-432</link>

		<dc:creator><![CDATA[Jonathan Boccara]]></dc:creator>
		<pubDate>Sat, 22 Jul 2017 22:27:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-432</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-430&quot;&gt;Val Baca&lt;/a&gt;.

Thanks, typo corrected.]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-430">Val Baca</a>.</p>
<p>Thanks, typo corrected.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Ryan Phelps		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-431</link>

		<dc:creator><![CDATA[Ryan Phelps]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 20:07:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-431</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-428&quot;&gt;Giannis Vrentzos&lt;/a&gt;.

I like your second one because most people find it easier to read positive logic in if() statements.  I&#039;d go even further and eliminate the else clauses since each branch is exclusive of the other.  This way you know they&#039;re not related to each other, and there is no further processing to be done

&lt;pre&gt;&lt;code class=&quot;c++&quot;&gt;
void Item::applyDiscount() {
  if(hasRedTag()) {
    return;
  }

  if(isSoldOnlineOnly()) {
    if(hasSpecialDayDiscount()) {
      price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
    }
    return;
  }

  price_ *= 1 - getSaleDiscount();
}&lt;/code&gt;&lt;/pre&gt;]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-428">Giannis Vrentzos</a>.</p>
<p>I like your second one because most people find it easier to read positive logic in if() statements.  I&#8217;d go even further and eliminate the else clauses since each branch is exclusive of the other.  This way you know they&#8217;re not related to each other, and there is no further processing to be done</p>
<pre><code class="c++">
void Item::applyDiscount() {
  if(hasRedTag()) {
    return;
  }

  if(isSoldOnlineOnly()) {
    if(hasSpecialDayDiscount()) {
      price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
    }
    return;
  }

  price_ *= 1 - getSaleDiscount();
}</code></pre>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Val Baca		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-430</link>

		<dc:creator><![CDATA[Val Baca]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 17:43:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-430</guid>

					<description><![CDATA[Minor typo:
s/tun/return
And nothing says that a compact if will tun faster than a more developed one.]]></description>
			<content:encoded><![CDATA[<p>Minor typo:<br />
s/tun/return<br />
And nothing says that a compact if will tun faster than a more developed one.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Jonathan Boccara		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-429</link>

		<dc:creator><![CDATA[Jonathan Boccara]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 15:45:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-429</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-428&quot;&gt;Giannis Vrentzos&lt;/a&gt;.

Looks good to me!]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-428">Giannis Vrentzos</a>.</p>
<p>Looks good to me!</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Giannis Vrentzos		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-428</link>

		<dc:creator><![CDATA[Giannis Vrentzos]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 15:41:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-428</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-427&quot;&gt;Jonathan Boccara&lt;/a&gt;.

Your version follows the specification in a more clear way, so adding only the guard and keeping the rest of the code as is could be a better alternative. e.g. 

&lt;pre&gt;&lt;code&gt;
void Item::applyDiscount()
{
    if (hasRedTag()) {
        return;
    }
    
    if (isSoldOnlineOnly()) {
        if (hasSpecialDayDiscount()) {
            price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
        }
    } else {
        price_ *= 1 - getSaleDiscount();
    }
}
&lt;/pre&gt;&lt;/code&gt;]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-427">Jonathan Boccara</a>.</p>
<p>Your version follows the specification in a more clear way, so adding only the guard and keeping the rest of the code as is could be a better alternative. e.g. </p>
<pre><code>
void Item::applyDiscount()
{
    if (hasRedTag()) {
        return;
    }
    
    if (isSoldOnlineOnly()) {
        if (hasSpecialDayDiscount()) {
            price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
        }
    } else {
        price_ *= 1 - getSaleDiscount();
    }
}
</code></pre>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Jonathan Boccara		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-427</link>

		<dc:creator><![CDATA[Jonathan Boccara]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 13:57:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-427</guid>

					<description><![CDATA[In reply to &lt;a href=&quot;https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-426&quot;&gt;Giannis Vrentzos&lt;/a&gt;.

Thanks Giannis, glad you liked it.
I think the guard is a good idea; it decreases nesting while following the spec. I actually intended to write about this in a later post, as a matter of fact.
And do you find the rest of your snippet more natural? This would typically be a case to discuss with the domain people then.]]></description>
			<content:encoded><![CDATA[<p>In reply to <a href="https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-426">Giannis Vrentzos</a>.</p>
<p>Thanks Giannis, glad you liked it.<br />
I think the guard is a good idea; it decreases nesting while following the spec. I actually intended to write about this in a later post, as a matter of fact.<br />
And do you find the rest of your snippet more natural? This would typically be a case to discuss with the domain people then.</p>
]]></content:encoded>
		
			</item>
		<item>
		<title>
		By: Giannis Vrentzos		</title>
		<link>https://www.fluentcpp.com/2017/07/21/making-if-statements-understandable/#comment-426</link>

		<dc:creator><![CDATA[Giannis Vrentzos]]></dc:creator>
		<pubDate>Fri, 21 Jul 2017 12:47:00 +0000</pubDate>
		<guid isPermaLink="false">https://www.fluentcpp.com/?p=1501#comment-426</guid>

					<description><![CDATA[Great post, Jonathan!

How about something like the following as an alternative solution for the applyDiscount method?

&lt;pre&gt;&lt;code&gt;
void Item::applyDiscount()
{
    if (hasRedTag()) {
        return;
    }
  
    if (!isSoldOnlineOnly()) {
        price_ *= 1 - getSaleDiscount();
    } else if (hasSpecialDayDiscount()) {
        price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
    }
}
&lt;/code&gt;&lt;/pre&gt;]]></description>
			<content:encoded><![CDATA[<p>Great post, Jonathan!</p>
<p>How about something like the following as an alternative solution for the applyDiscount method?</p>
<pre><code>
void Item::applyDiscount()
{
    if (hasRedTag()) {
        return;
    }
  
    if (!isSoldOnlineOnly()) {
        price_ *= 1 - getSaleDiscount();
    } else if (hasSpecialDayDiscount()) {
        price_ = std::max(minimumPrice, price_ - getSpecialDayDiscount());
    }
}
</code></pre>
]]></content:encoded>
		
			</item>
	</channel>
</rss>
