<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://isaak.dev/feed.xml" rel="self" type="application/atom+xml" /><link href="https://isaak.dev/" rel="alternate" type="text/html" /><updated>2026-01-07T10:41:45+00:00</updated><id>https://isaak.dev/feed.xml</id><title type="html">Isaak’s Blog</title><subtitle>Thoughts about software development.</subtitle><author><name>Isaak Uchakaev</name></author><entry><title type="html">Is it Easier to Ask Forgiveness than Permission or to Look Before You Leap?</title><link href="https://isaak.dev/eafp-and-lbyl" rel="alternate" type="text/html" title="Is it Easier to Ask Forgiveness than Permission or to Look Before You Leap?" /><published>2023-08-06T00:00:00+00:00</published><updated>2023-08-06T00:00:00+00:00</updated><id>https://isaak.dev/eafp-and-lbyl</id><content type="html" xml:base="https://isaak.dev/eafp-and-lbyl"><![CDATA[<p>The purpose of this article is to discuss two opposing approaches to writing
code: <a href="https://docs.python.org/3/glossary.html#term-EAFP">EAFP</a>
and <a href="https://docs.python.org/3/glossary.html#term-LBYL">LBYL</a>. 
There is no need for a long introduction, so let’s dive in.</p>

<h2 id="the-problem">The Problem</h2>

<p>Suppose we have received a response from an API call, with following structure:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">response</span> <span class="o">=</span> <span class="p">{</span>
    <span class="s">"data"</span><span class="p">:</span> <span class="p">{</span>
        <span class="s">"id"</span><span class="p">:</span> <span class="mi">241332</span><span class="p">,</span>
        <span class="s">"recipient"</span><span class="p">:</span> <span class="p">{</span>
            <span class="s">"city"</span><span class="p">:</span> <span class="s">"Palo Alto"</span><span class="p">,</span>
            <span class="s">"country"</span><span class="p">:</span> <span class="s">"US"</span><span class="p">,</span>
            <span class="s">"address"</span><span class="p">:</span> <span class="s">"1 Infinite Loop"</span><span class="p">,</span>
            <span class="s">"postal_code"</span><span class="p">:</span> <span class="s">"12345"</span><span class="p">,</span>
            <span class="s">"state"</span><span class="p">:</span> <span class="s">"CA"</span><span class="p">,</span>
            <span class="s">"name"</span><span class="p">:</span> <span class="s">"Tim Cook"</span><span class="p">,</span>
            <span class="s">"phone"</span><span class="p">:</span> <span class="s">"+1234567890"</span><span class="p">,</span>
            <span class="s">"email"</span><span class="p">:</span> <span class="s">"tcook@apple.com"</span>
        <span class="p">},</span>
        <span class="s">"cost"</span><span class="p">:</span> <span class="mf">1099.00</span><span class="p">,</span>
        <span class="s">"currency"</span><span class="p">:</span> <span class="s">"USD"</span><span class="p">,</span>
        <span class="s">"name"</span><span class="p">:</span> <span class="s">"Google Pixel 7 Pro"</span><span class="p">,</span>
        <span class="s">"quantity"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
        <span class="s">"color"</span><span class="p">:</span> <span class="s">"Obsidian"</span><span class="p">,</span>
        <span class="s">"capacity"</span><span class="p">:</span> <span class="s">"512GB"</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Our goal is to retrieve the <code class="language-plaintext highlighter-rouge">email</code> of the recipient. We assume that any field may be missing to add complexity.</p>

<h2 id="look-before-you-leap">Look Before You Leap</h2>

<p>The <em>LBLY</em> states that you should check for preconditions before performing any actions (like calling functions,
accessing dictionary keys, or object attributes).</p>

<p>Just like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_user_email</span><span class="p">(</span><span class="n">response</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">data</span> <span class="o">=</span> <span class="n">response</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'data'</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">data</span><span class="p">:</span>
        <span class="n">recipient</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'recipient'</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">recipient</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">recipient</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'email'</span><span class="p">)</span>
    <span class="k">return</span> <span class="bp">None</span>
</code></pre></div></div>

<p>This approach is the most commonly used in programming, but it can also result in a lot of repetitive and unnecessary
code, which can be challenging to maintain. So, why not attempt to access the key and handle the exception if it doesn’t exist? 
This is precisely where <em>EAFP</em> comes into play.</p>

<h2 id="easier-to-ask-forgiveness-than-permission">Easier to Ask Forgiveness than Permission</h2>

<p>The <em>EAFP</em> states that it’s simpler to perform an action and then handle error, instead of checking all necessary
conditions beforehand.</p>

<p>Example:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">get_user_email</span><span class="p">(</span><span class="n">response</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">:</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">response</span><span class="p">[</span><span class="s">'data'</span><span class="p">][</span><span class="s">'recipient'</span><span class="p">][</span><span class="s">'email'</span><span class="p">]</span>
    <span class="k">except</span> <span class="nb">KeyError</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>
</code></pre></div></div>

<p>One essential thing to bear in mind is that we should always catch the most specific exception available. In this
example, we are catching a <code class="language-plaintext highlighter-rouge">KeyError</code> exception, which is raised when a dictionary key is not found. If we catch a
general <code class="language-plaintext highlighter-rouge">Exception</code> we may inadvertently catch exceptions that we weren’t expecting, leading to unexpected behavior.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Neither of these approaches is superior to the other. Both approaches have their pros and cons, and the
choice of which one to use and when ultimately depends on the specific requirements and context of the program.</p>

<p>That’s all for today. See you next time!</p>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[The aim of this article is to explore two contrasting approaches to code writing: EAFP and LBYL.]]></summary></entry><entry><title type="html">The SOLID Principles for Solid Developers.</title><link href="https://isaak.dev/solid-principles-for-solid-devs" rel="alternate" type="text/html" title="The SOLID Principles for Solid Developers." /><published>2023-08-04T00:00:00+00:00</published><updated>2023-08-04T00:00:00+00:00</updated><id>https://isaak.dev/solid-principles-for-solid-devs</id><content type="html" xml:base="https://isaak.dev/solid-principles-for-solid-devs"><![CDATA[<p>Let me guess, you were browsing jobs on LinkedIn and saw a requirement to understand <strong>SOLID</strong> principles and decided
to google what the heck SOLID is? Either way, you’ve come to the right place.</p>

<p>This article is not meant to be SOLID-propaganda, and I’m not going to convince you that you are obligated to adhere
to SOLID principles. My purpose is simple — to tell you what SOLID is and how it works. It’s up to you to apply these
principles in your work or not. Anyway, after reading this article, you will be able to defend/hate SOLID with 
a frothing at the mouth.</p>

<h2 id="definition">Definition</h2>

<p>In short, <strong>SOLID</strong> is a set of five principles of object-oriented design focused on making software more modular,
maintainable, and scalable.</p>

<p>The acronym <strong>SOLID</strong> stands for:</p>

<ul>
  <li><strong>S</strong> - Single Responsibility Principle (SRP)</li>
  <li><strong>O</strong> - Open/Closed Principle (OCP)</li>
  <li><strong>L</strong> - Liskov Substitution Principle (LSP)</li>
  <li><strong>I</strong> - Interface Segregation Principle (ISP)</li>
  <li><strong>D</strong> - Dependency Inversion Principle (DIP)</li>
</ul>

<p>Let’s examine each of these principles separately.</p>

<h2 id="single-responsibility-principle">Single Responsibility Principle</h2>

<p>The Single Responsibility Principle (SRP) states that a class should have only one reason to change, meaning that it
should have only one responsibility or task to perform. By following this principle, a class’s functionality is more
focused, leading to improved manageability and comprehension.</p>

<p>First, let’s look at code which violates <em>SRP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">email</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">password</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">password</span> <span class="o">=</span> <span class="n">password</span>

    <span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Logging in user: </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">logout</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Logging out user: </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">send_notification</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sending notification to </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Serializing user: </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<p>It’s evident that the <code class="language-plaintext highlighter-rouge">User</code> class violates the <em>SRP</em> since it’s accountable for numerous tasks, namely:</p>

<ul>
  <li>Storing user information</li>
  <li>Authenticating users</li>
  <li>Sending notifications</li>
  <li>Serializing users</li>
</ul>

<p>If any one of these responsibilities changes, it may affect the entire <code class="language-plaintext highlighter-rouge">User</code> class. For instance, if the method for
sending notifications needs to be updated or changed, it could potentially break the code for the entire <code class="language-plaintext highlighter-rouge">User</code>
class, including the methods for logging in.</p>

<p>By following <em>SRP</em>, our goal is to separate the different responsibilities into their own classes, so that each class is
responsible for only one thing. For example, a <code class="language-plaintext highlighter-rouge">User</code> class could be responsible for storing user information only,
while separate <code class="language-plaintext highlighter-rouge">Authentication</code>, <code class="language-plaintext highlighter-rouge">NotificationSender</code>, and <code class="language-plaintext highlighter-rouge">UserSerializer</code> classes could be responsible for their
respective tasks.</p>

<p>Here’s an example of how we can refactor the <code class="language-plaintext highlighter-rouge">User</code> class to adhere to the <em>SRP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">email</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">password</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">password</span> <span class="o">=</span> <span class="n">password</span>

    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">name</span><span class="si">}</span><span class="s"> &lt;</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">email</span><span class="si">}</span><span class="s">&gt;"</span>

    <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="s">"User('</span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">email</span><span class="si">}</span><span class="s">')"</span>


<span class="k">class</span> <span class="nc">UserSerializer</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">user</span>

    <span class="k">def</span> <span class="nf">serialize</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Serializing user: </span><span class="si">{</span><span class="bp">self</span><span class="p">.</span><span class="n">user</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Authentication</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">login</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Logging in user: </span><span class="si">{</span><span class="n">user</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">logout</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Logging out user: </span><span class="si">{</span><span class="n">user</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">NotificationSender</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">send_notification</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sending notification to </span><span class="si">{</span><span class="n">user</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span>
        <span class="s">"Winston Churchill"</span><span class="p">,</span>
        <span class="s">"winston@churchill.uk"</span><span class="p">,</span>
        <span class="s">"we-shall-fight"</span>
    <span class="p">)</span>

    <span class="c1"># Authentication
</span>    <span class="n">auth</span> <span class="o">=</span> <span class="n">Authentication</span><span class="p">()</span>
    <span class="n">auth</span><span class="p">.</span><span class="n">login</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="n">auth</span><span class="p">.</span><span class="n">logout</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>

    <span class="c1"># Notification
</span>    <span class="n">notification_sender</span> <span class="o">=</span> <span class="n">NotificationSender</span><span class="p">()</span>
    <span class="n">notification_sender</span><span class="p">.</span><span class="n">send_notification</span><span class="p">(</span>
        <span class="n">user</span><span class="p">,</span> <span class="s">"Beware of the German U-boats!"</span><span class="p">,</span>
    <span class="p">)</span>

    <span class="c1"># Serialization
</span>    <span class="n">user_serializer</span> <span class="o">=</span> <span class="n">UserSerializer</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="n">user_serializer</span><span class="p">.</span><span class="n">serialize</span><span class="p">()</span>
</code></pre></div></div>

<p>As you can see, it’s pretty clear and I have nothing more to add here.</p>

<h2 id="openclosed-principle">Open/Closed Principle</h2>

<p>The Open/Closed Principle (OCP) states that a class should be open for extension but closed for modification. This means
that we should be able to add new functionality to a class without changing its existing code.</p>

<p>Let’s examine the code that violates the <em>OCP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">NotificationService</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">notification</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">notification</span> <span class="o">=</span> <span class="n">notification</span>

    <span class="k">def</span> <span class="nf">send_notification</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">if</span> <span class="bp">self</span><span class="p">.</span><span class="n">notification</span> <span class="o">==</span> <span class="s">"email"</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sending email with message: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">notification</span> <span class="o">==</span> <span class="s">"push"</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sending SMS with message: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
        <span class="k">elif</span> <span class="bp">self</span><span class="p">.</span><span class="n">notification</span> <span class="o">==</span> <span class="s">"slack"</span><span class="p">:</span>
            <span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Sending whatsapp with message: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">notification_service</span> <span class="o">=</span> <span class="n">NotificationService</span><span class="p">(</span><span class="s">"slack"</span><span class="p">)</span>
    <span class="n">notification_service</span><span class="p">.</span><span class="n">send_notification</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
</code></pre></div></div>

<p>This code violates the <em>OCP</em> because the <code class="language-plaintext highlighter-rouge">NotificationService</code> class is not closed for modification. If we want to
add a new notification method, we have to modify the existing code in the <code class="language-plaintext highlighter-rouge">send_notification</code> method.</p>

<p>Let’s modify the code to follow to the OCP:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">Notification</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">PushNotification</span><span class="p">(</span><span class="n">Notification</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Sending push notification..."</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">EmailNotification</span><span class="p">(</span><span class="n">Notification</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Sending email notification..."</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">SlackNotification</span><span class="p">(</span><span class="n">Notification</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">send</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Sending slack notification..."</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">NotificationService</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">notification</span><span class="p">:</span> <span class="n">Notification</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">notification</span> <span class="o">=</span> <span class="n">notification</span>

    <span class="k">def</span> <span class="nf">send_notification</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">notification</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">notification_service</span> <span class="o">=</span> <span class="n">NotificationService</span><span class="p">(</span><span class="n">SlackNotification</span><span class="p">())</span>
    <span class="n">notification_service</span><span class="p">.</span><span class="n">send_notification</span><span class="p">(</span><span class="s">"German U-boats spotted!"</span><span class="p">)</span>
</code></pre></div></div>

<p>In this example, the <code class="language-plaintext highlighter-rouge">NotificationService</code> class is closed for modification because we can add new notification
methods without changing the existing code. For instance, if we want to add a new <code class="language-plaintext highlighter-rouge">SMSNotification</code> class, we can
simply create a new class that extends the <code class="language-plaintext highlighter-rouge">Notification</code> class and implement the <code class="language-plaintext highlighter-rouge">send</code> method. Such a design
allows us to add new notification methods without changing the existing code.</p>

<h2 id="liskov-substitution-principle">Liskov Substitution Principle</h2>

<p>The LSP states that a subclass should be substitutable for its superclass without changing the correctness of the
program. In other words, if we replace an instance of a superclass with an instance of its subclass, the program should
still behave as expected.</p>

<p>Let’s take a look at the following example which violates the <em>LSP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">ICharacter</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>
    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">Human</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Hello, I am a human"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Polish</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Dzień dobry, kurwa!"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">French</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Bonjour!"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">German</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">RuntimeError</span><span class="p">(</span><span class="s">"Nien!"</span><span class="p">)</span>
</code></pre></div></div>

<p>In this example, the <code class="language-plaintext highlighter-rouge">German</code> class is a subclass of <code class="language-plaintext highlighter-rouge">Human</code>. However, it violates the <em>LSP</em> because it
changes the behavior of the <code class="language-plaintext highlighter-rouge">German</code>. The <code class="language-plaintext highlighter-rouge">Human</code> class can greet, but the <code class="language-plaintext highlighter-rouge">German</code> class cannot. This means
that code that expects a <code class="language-plaintext highlighter-rouge">Human</code> instance may behave unexpectedly or fail when given a <code class="language-plaintext highlighter-rouge">German</code> instance.</p>

<p>Let’s refactor code to make it follow <em>LSP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">ICharacter</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>
    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">Human</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Hello, I am a human"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Polish</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Dzień dobry, kurwa!"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">French</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Bonjour!"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">German</span><span class="p">(</span><span class="n">Human</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Hallo!"</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="interface-segregation-principle">Interface Segregation Principle</h2>

<p>The Interface Segregation Principle (ISP) states that a class shouldn’t be forced to depend on methods it does not use.
In other words, we should break down large interfaces into smaller ones, more focused on the needs of each class.</p>

<p>Let’s take a look at the following example which violates the <em>ISP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">ICharacter</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>
    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">pull_out_rpg</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">Warrior</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Warrior is attacking"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Warrior is walking"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">pull_out_rpg</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Pulling out motherfucking RPG-7"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Civilian</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">pull_out_rpg</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="c1"># Jesus Christ, what kind of civilian is this? 
</span>        <span class="c1"># Where the hell did this bastard get a thermoboric RPG shell?
</span>        <span class="k">print</span><span class="p">(</span><span class="s">"Pulling out motherfucking RPG-7 with thermobaric shell"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="c1"># Why the hell would a civilian attack?
</span>        <span class="k">print</span><span class="p">(</span><span class="s">"Civilian is attacking"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Civilian is walking"</span><span class="p">)</span>

</code></pre></div></div>

<p>In this example, we define an <code class="language-plaintext highlighter-rouge">ICharacter</code> interface that has three methods:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">attack()</code></li>
  <li><code class="language-plaintext highlighter-rouge">walk()</code></li>
  <li><code class="language-plaintext highlighter-rouge">pull_out_rpg()</code></li>
</ul>

<p>We have a violation of the <em>ISP</em> in the implementation of the <code class="language-plaintext highlighter-rouge">ICharacter</code> interface, where we
define two concrete classes <code class="language-plaintext highlighter-rouge">Warrior</code> and <code class="language-plaintext highlighter-rouge">Civilian</code>. The problem is that <code class="language-plaintext highlighter-rouge">Civilian</code> is forced to implement the <code class="language-plaintext highlighter-rouge">attack</code>
and <code class="language-plaintext highlighter-rouge">pull_out_rpg</code> methods, even though it may not (haha) need to use them.</p>

<p>If we don’t implement these methods in the <code class="language-plaintext highlighter-rouge">Civilian</code> class, we’ll get an error:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TypeError: Can't instantiate abstract class Civilian with abstract methods attack, pull_out_rpg
</code></pre></div></div>

<p>To avoid such problems, it’s highly recommendable to break down large interfaces into smaller ones, more focused
on the needs of each class. Let’s refactor the code to make it follow <em>ISP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">ICharacter</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">IWarrior</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>

    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">pull_out_rpg</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">Warrior</span><span class="p">(</span><span class="n">IWarrior</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">attack</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Warrior is attacking"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Warrior is walking"</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">pull_out_rpg</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Pulling out motherfucking RPG-7"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">Civilian</span><span class="p">(</span><span class="n">ICharacter</span><span class="p">):</span>

    <span class="k">def</span> <span class="nf">walk</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Civilian is walking"</span><span class="p">)</span>
</code></pre></div></div>

<p>Now we no longer arm civilians with hand-held anti-tank grenade launchers, and the world is a little safer.</p>

<h2 id="dependency-inversion-principle">Dependency Inversion Principle</h2>

<p>The Dependency Inversion Principle (DIP) states that high-level classes should not depend on low-level classes. Instead,
they should both depend on abstractions. Abstractions should not depend on details, but details should depend on
abstractions.</p>

<p>Let’s examine <em>DIP</em> violation:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">StripePaymentGateway</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with Stripe"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">KlarnaPaymentGateway</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with Klarna"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">BitPayPaymentGateway</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with BitPay"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">PaymentProcessor</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">stripe</span> <span class="o">=</span> <span class="n">StripePaymentGateway</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">klarna</span> <span class="o">=</span> <span class="n">KlarnaPaymentGateway</span><span class="p">()</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">bitpay</span> <span class="o">=</span> <span class="n">BitPayPaymentGateway</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">process_payment</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">payment_gateway</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">payment_gateway</span> <span class="o">==</span> <span class="s">"stripe"</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">stripe</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>
        <span class="k">elif</span> <span class="n">payment_gateway</span> <span class="o">==</span> <span class="s">"klarna"</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">klarna</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>
        <span class="k">elif</span> <span class="n">payment_gateway</span> <span class="o">==</span> <span class="s">"bitpay"</span><span class="p">:</span>
            <span class="bp">self</span><span class="p">.</span><span class="n">bitpay</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">payment_processor</span> <span class="o">=</span> <span class="n">PaymentProcessor</span><span class="p">()</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">process_payment</span><span class="p">(</span><span class="s">'stripe'</span><span class="p">)</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">process_payment</span><span class="p">(</span><span class="s">'klarna'</span><span class="p">)</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">process_payment</span><span class="p">(</span><span class="s">'bitpay'</span><span class="p">)</span>
</code></pre></div></div>

<p>In this example, we have a <code class="language-plaintext highlighter-rouge">PaymentProcessor</code> class which has a hard dependencies on concrete implementations of payment
gateways. This is a violation of the <em>DIP</em> because the <code class="language-plaintext highlighter-rouge">PaymentProcessor</code> class is a high-level class that depends on
low-level classes. This means that if we want to add a new payment gateway, we’ll have to modify the <code class="language-plaintext highlighter-rouge">PaymentProcessor</code>
class which potentially can break the code.</p>

<p>Let’s refactor our payment gateway to make it follow <em>DIP</em>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">abc</span>


<span class="k">class</span> <span class="nc">PaymentGateway</span><span class="p">(</span><span class="n">abc</span><span class="p">.</span><span class="n">ABC</span><span class="p">):</span>
    <span class="o">@</span><span class="n">abc</span><span class="p">.</span><span class="n">abstractmethod</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nb">NotImplementedError</span>


<span class="k">class</span> <span class="nc">StripePaymentGateway</span><span class="p">(</span><span class="n">PaymentGateway</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with Stripe"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">KlarnaPaymentGateway</span><span class="p">(</span><span class="n">PaymentGateway</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with Klarna"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">BitPayPaymentGateway</span><span class="p">(</span><span class="n">PaymentGateway</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">"Paying with BitPay"</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">PaymentProcessor</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">payment_gateway</span><span class="p">:</span> <span class="n">PaymentGateway</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">payment_gateway</span> <span class="o">=</span> <span class="n">payment_gateway</span>

    <span class="k">def</span> <span class="nf">pay</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="bp">self</span><span class="p">.</span><span class="n">payment_gateway</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>


<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span>
    <span class="n">payment_processor</span> <span class="o">=</span> <span class="n">PaymentProcessor</span><span class="p">(</span><span class="n">StripePaymentGateway</span><span class="p">())</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>

    <span class="n">payment_processor</span> <span class="o">=</span> <span class="n">PaymentProcessor</span><span class="p">(</span><span class="n">KlarnaPaymentGateway</span><span class="p">())</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>

    <span class="n">payment_processor</span> <span class="o">=</span> <span class="n">PaymentProcessor</span><span class="p">(</span><span class="n">BitPayPaymentGateway</span><span class="p">())</span>
    <span class="n">payment_processor</span><span class="p">.</span><span class="n">pay</span><span class="p">()</span>
</code></pre></div></div>

<p>In this example, we have a <code class="language-plaintext highlighter-rouge">PaymentProcessor</code> class that depends on an abstraction <code class="language-plaintext highlighter-rouge">PaymentGateway</code>. This means that we
can add as many payment gateways as we want without modifying the <code class="language-plaintext highlighter-rouge">PaymentProcessor</code> class itself.</p>

<h2 id="conclusion">Conclusion</h2>

<p>In this article, we have explored the SOLID principles and their implementation in Python. We have discussed how the
<em>SRP</em> can help in creating more organized and manageable classes, and how the <em>OCP</em> can make our code more extensible.
We have also examined the LSP to achieve more flexible code, the ISP for maintainable code, and even had a bit of fun
disarming civilians. Finally, we have explored how the <em>DIP</em> can increase code reusability.</p>

<p>That’s all for today. See you next time!</p>

<h2 id="further-reading">Further Reading</h2>

<ul>
  <li>Robert C. Martin - Clean Architecture: A Craftsman’s Guide to Software Structure and Design.</li>
</ul>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[In this article, we'll learn about SOLID principles and how to apply them in Python to write more flexible, maintainable, and scalable code.]]></summary></entry><entry><title type="html">Generating Secrets in Clojure</title><link href="https://isaak.dev/generating-secrets-in-clojure" rel="alternate" type="text/html" title="Generating Secrets in Clojure" /><published>2022-10-03T00:00:00+00:00</published><updated>2022-10-03T00:00:00+00:00</updated><id>https://isaak.dev/generating-secrets-in-clojure</id><content type="html" xml:base="https://isaak.dev/generating-secrets-in-clojure"><![CDATA[<p>Generating secrets is a very important part of any security-sensitive application. In this article, I’m going to tell you about a low-level library that helps to generate secrets in Clojure.</p>

<p>If you’re familiar with Python, you might have heard of <a href="https://docs.python.org/3/library/secrets.html">secrets</a> module from Python’s standard library. Basically, 
the <a href="https://github.com/lk-geimfari/secrets.clj">secrets.clj</a> is just like Python’s secrets, but for Clojure — it’s a library designed to generate cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.</p>

<h2 id="installation">Installation</h2>

<p>Add <code class="language-plaintext highlighter-rouge">secrets.clj</code> to your <code class="language-plaintext highlighter-rouge">project.clj</code> file:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">likid_geimfari/secrets</span><span class="w"> </span><span class="s">"2.1.1"</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<p>then run <code class="language-plaintext highlighter-rouge">lein deps</code> to install it.</p>

<p>That’s it, you’re ready to go:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">ns</span><span class="w"> </span><span class="n">example.core</span><span class="w">
  </span><span class="p">(</span><span class="no">:require</span><span class="w"> </span><span class="p">[</span><span class="n">secrets.core</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">secrets.tools</span><span class="p">]</span><span class="w">
            </span><span class="p">[</span><span class="n">secrets.constants</span><span class="p">]))</span><span class="w">
</span></code></pre></div></div>

<h2 id="usage">Usage</h2>

<p>Typical use cases are:</p>

<ul>
  <li>Generating random numbers</li>
  <li>Creating passwords, SMS-codes and OTP</li>
  <li>Generating random tokens</li>
  <li>Generating password recovery URLs and session keys</li>
</ul>

<h5 id="secretscorerandbits-k">secrets.core/randbits k</h5>

<p>Generates a random integer with <code class="language-plaintext highlighter-rouge">k</code> random bits.</p>

<p>Example:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user=&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">secrets.core/randbits</span><span class="w"> </span><span class="mi">32</span><span class="p">)</span><span class="w">
</span><span class="mi">1530556122</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscorerandbelow-n">secrets.core/randbelow n</h5>

<p>This function generates a secure random integer in the range <code class="language-plaintext highlighter-rouge">[0, n)</code>, where <code class="language-plaintext highlighter-rouge">n</code> is the exclusive upper bound.</p>

<p>Example:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user=&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">secrets.core/randbelow</span><span class="w"> </span><span class="mi">9999</span><span class="p">)</span><span class="w">
</span><span class="mi">34</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscorechoice-seq">secrets.core/choice seq</h5>

<p>This function returns a random element from a non-empty sequence or throws an exception if the sequence is empty.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user=&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">secrets.core/choice</span><span class="w"> </span><span class="p">[</span><span class="s">"bob"</span><span class="w"> </span><span class="s">"alice"</span><span class="w"> </span><span class="s">"eve"</span><span class="p">])</span><span class="w">
</span><span class="s">"eve"</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscorechoices-seq">secrets.core/choices seq</h5>

<p>Just like <code class="language-plaintext highlighter-rouge">secrets.core/choice</code>, but this function returns a list of random elements picked from the sequence:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">secrets.core/choices</span><span class="w"> </span><span class="p">[</span><span class="s">"bob"</span><span class="w"> </span><span class="s">"alice"</span><span class="w"> </span><span class="s">"eve"</span><span class="p">]</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="s">"eve"</span><span class="w"> </span><span class="s">"alice"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscoretoken-hex-nbytes">secrets.core/token-hex nbytes</h5>

<p>Generates a secure random string in hexadecimal format. The string has <code class="language-plaintext highlighter-rouge">nbytes</code> random bytes, and each byte is converted to two hex digits. 
If n-bytes are not supplied, a reasonable default gets used, which is 32.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">user=&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">secrets.core/token-hex</span><span class="w"> </span><span class="mi">64</span><span class="p">)</span><span class="w">
</span><span class="s">"3a3e8e6636000dd3b7d39aa4316935f27c2f013d768f0c00f309efb453f34dbc673060db2cd8af288494892848"</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscoretoken-urlsafe-nbytes">secrets.core/token-urlsafe nbytes</h5>

<p>Generates a secure random string in URL-safe format.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">generate-password-recovery-url</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="s">"https://mydomain.com/reset="</span><span class="w"> </span><span class="p">(</span><span class="nf">secrets.core/token-urlsafe</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="nf">generate-password-recovery-url</span><span class="w"> </span><span class="mi">64</span><span class="p">)</span><span class="w">
</span><span class="s">"https://mydomain.com/reset=TItm04q8by00MRMcNBt7I3Yx-wSxyUa79isRLNyQJCd8K75RnqUahwcWA_rURBt1clknJiRGrubapGaUrEUnSw"</span><span class="w">
</span></code></pre></div></div>

<h5 id="secretscoretoken-bytes-nbytes">secrets.core/token-bytes nbytes</h5>

<p>Generates a secure random string in bytes format.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">secrets.core/token-bytes</span><span class="w"> </span><span class="mi">16</span><span class="p">)</span><span class="w">
</span><span class="o">#</span><span class="n">object</span><span class="p">[</span><span class="s">"[B"</span><span class="w"> </span><span class="mi">0</span><span class="n">x3b2454e9</span><span class="w"> </span><span class="s">"[B@3b2454e9"</span><span class="p">]</span><span class="w">
</span></code></pre></div></div>

<h2 id="how-many-bytes-should-tokens-use">How many bytes should tokens use?</h2>

<p>To be secure against brute-force attacks, tokens need to have sufficient randomness.
The number of random bits needed for a token depends on the application, but 256 bits 
is considered to be cryptographically strong.</p>

<p>Personally, I would recommend using 64 bytes (<code class="language-plaintext highlighter-rouge">512 bits</code>).</p>

<h2 id="links">Links</h2>

<ul>
  <li>Repository: <a href="https://github.com/lk-geimfari/secrets.clj">lk-geimfari/secrets.clj</a></li>
  <li>Documentation: <a href="https://cljdoc.org/d/likid_geimfari/secrets/2.1.0/doc/readme">https://cljdoc.org/</a></li>
  <li>Clojars: <a href="https://clojars.org/likid_geimfari/secrets">likid_geimfari/secrets</a></li>
</ul>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[Generating secrets is a very important part of any security-sensitive application. In this article, I'm going to tell you about a low-level library that helps to generate secrets in Clojure.]]></summary></entry><entry><title type="html">Python Libraries to Make Your Code Readable, Reliable and Maintainable</title><link href="https://isaak.dev/python-libraries-to-make-your-code-readable-and-maintainable" rel="alternate" type="text/html" title="Python Libraries to Make Your Code Readable, Reliable and Maintainable" /><published>2020-08-24T00:00:00+00:00</published><updated>2020-08-24T00:00:00+00:00</updated><id>https://isaak.dev/python-libraries-to-make-your-code-readable-and-maintainable</id><content type="html" xml:base="https://isaak.dev/python-libraries-to-make-your-code-readable-and-maintainable"><![CDATA[<p>Experienced programmers understand perfectly well that in development they spend most of the time reading code 
and therefore they treat the process of writing code with the deepest trepidation (and sometimes with fanaticism). 
To write quality and maintainable code, you need to take the time to write tests and integrate QA tools. There is a 
whole technique aimed at test-driven development (<a href="https://en.wikipedia.org/wiki/Test-driven_development">TDD</a>) and I will not devote this article to the topic of testing as 
such. Tests are absolutely necessary and there is nothing to discuss. In this article, we are going to talk about tools 
that help you write quality Python code.</p>

<p>Table of content:</p>

<ul>
  <li><a href="#testing-frameworks">Testing Frameworks</a></li>
  <li><a href="#test-runners">Test Runners</a></li>
  <li><a href="#e2e-testing-gui--frontend">E2E Testing</a></li>
  <li><a href="#fake-data">Fake Data</a></li>
  <li><a href="#mocking">Mocking</a></li>
  <li><a href="#code-coverage">Code coverage</a></li>
  <li><a href="#object-factories">Object Factories</a></li>
  <li><a href="#code-style">Code Style</a></li>
  <li><a href="#typing">Typing</a></li>
</ul>

<h2 id="testing-frameworks">Testing Frameworks</h2>

<p><a href="https://github.com/pytest-dev/pytest/"><strong>pytest</strong></a> is a framework that makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries.</p>

<p>Features</p>

<ul>
  <li>Detailed info on failing assert statements;</li>
  <li>Auto-discovery of test modules and functions;</li>
  <li>Modular fixtures for managing small or parametrized long-lived test resources;</li>
  <li>Can run <code class="language-plaintext highlighter-rouge">unittest</code> and nose test suites out of the box;</li>
  <li><code class="language-plaintext highlighter-rouge">Python 3.5+</code> and <code class="language-plaintext highlighter-rouge">PyPy 3</code>;</li>
  <li>Rich plugin architecture, with over 315+ external plugins and thriving community;</li>
</ul>

<p><br /></p>

<p><a href="https://github.com/HypothesisWorks/hypothesis"><strong>Hypothesis</strong></a>  is a family of testing libraries that let you write 
tests parametrized by a source of examples. A Hypothesis implementation then generates simple and comprehensible 
examples that make your tests fail. This simplifies writing your tests and makes them more powerful at the same time, 
by letting software automate the boring bits and do them to a higher standard than a human would, freeing you to focus 
on the higher-level test logic.</p>

<p><br /></p>

<p><a href="https://github.com/robotframework/robotframework"><strong>Robot Framework</strong></a> is a generic open-source automation framework 
for acceptance testing, acceptance test-driven development (ATDD), and robotic process automation (RPA). 
It has simple plain text syntax and it can be extended easily with libraries implemented using Python or Java.</p>

<p><br /></p>

<p><a href="https://docs.python.org/3/library/unittest.html"><strong>unittest</strong></a> is a unit testing framework from Python’s stdlib, 
which was originally inspired by JUnit and has a similar flavor as major unit testing frameworks in other languages. 
It supports test automation, sharing of setup and shutdown code for tests, aggregation of tests into collections, 
and independence of the tests from the reporting framework.</p>

<p><br /></p>

<h2 id="test-runners">Test Runners</h2>

<p><a href="https://github.com/tox-dev/tox"><strong>tox</strong></a> is aims to automate and standardize testing in Python. 
It is part of a larger vision of easing the packaging, testing and release process of Python software.</p>

<p>tox is a generic virtual environment management and test command line tool you can use for:</p>

<ul>
  <li>checking your package builds and installs correctly under different environments (such as different Python
implementations, versions or installation dependencies),</li>
  <li>running your tests in each of the environments with the test tool of choice,</li>
  <li>acting as a frontend to continuous integration servers, greatly reducing boilerplate and merging CI and shell-based
testing.</li>
</ul>

<p><br /></p>

<h2 id="e2e-testing-gui--frontend">E2E Testing (GUI / Frontend)</h2>

<p><a href="https://github.com/SeleniumHQ/selenium/"><strong>Selenium</strong></a> is an umbrella project encapsulating a variety of tools and 
libraries enabling web browser automation. Selenium specifically provides an infrastructure for the W3C WebDriver 
specification — a platform and language-neutral coding interface compatible with all major web browsers.</p>

<p><br /></p>

<p><a href="https://github.com/locustio/locust"><strong>Locust</strong></a> is an easy to use, scriptable, and scalable performance testing tool.
 You define the behavior of your users in regular Python code, instead of using a clunky UI or domain-specific 
 language. This makes Locust infinitely expandable and very developer-friendly.</p>

<p><br /></p>

<p><a href="https://github.com/DevExpress/testcafe"><strong>TestCafe</strong></a> is a Node.js tool to automate end-to-end web testing. Write 
tests in JS or TypeScript, run them, and view results.</p>

<ul>
  <li><strong>Works on all popular environments</strong>: TestCafe runs on Windows, MacOS, and Linux. It supports desktop, mobile, remote and cloud <a href="https://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/browsers/browser-support.html">browsers</a> (UI or headless).</li>
  <li><strong>1 minute to set up</strong>: You <a href="https://devexpress.github.io/testcafe/faq/#i-have-heard-that-testcafe-does-not-use-selenium-how-does-it-operate">do not need WebDriver</a> or any other testing software. Install TestCafe with one command, and you are ready to test: <code class="language-plaintext highlighter-rouge">npm install -g testcafe</code></li>
  <li><strong>Free and open source</strong>: TestCafe is free to use under the <a href="https://github.com/DevExpress/testcafe/blob/master/LICENSE">MIT license</a>. <a href="#plugins">Plugins</a> provide custom reports, integration with other tools, launching tests from IDE, etc. You can use the plugins made by the GitHub community or make your own.</li>
</ul>

<p><br /></p>

<p><a href="https://github.com/asweigart/pyautogui"><strong>PyAutoGUI</strong></a> is a cross-platform GUI automation Python module for human beings. 
Used to programmatically control the mouse &amp; keyboard.</p>

<p><br /></p>

<h2 id="fake-data">Fake Data</h2>

<p><a href="https://github.com/lk-geimfari/mimesis"><strong>Mimesis</strong></a> is a high-performance fake data generator for Python, which
provides data for a variety of purposes in a variety of languages. The
fake data could be used to populate a testing database, create fake API
endpoints, create JSON and XML files of arbitrary structure, anonymize
data taken from production and etc.</p>

<p>The key features are:</p>

<ul>
  <li><strong>Performance</strong>: The <a href="https://mimesis.name/foreword.html#performance">fastest</a> data generator available for Python.</li>
  <li><strong>Extensibility</strong>: You can create your own data providers and use them with Mimesis.</li>
  <li><strong>Generic data provider</strong>: The <a href="https://mimesis.name/getting_started.html#generic-provider">simplified</a> access to all the providers from a single object.</li>
  <li><strong>Multilingual</strong>: Supports data for <a href="https://mimesis.name/getting_started.html#locales">a lot of languages</a>.</li>
  <li><strong>Data variety</strong>: Supports <a href="https://mimesis.name/api.html">a lot of data providers</a> for a variety of purposes.</li>
  <li><strong>Schema-based generators</strong>: Provides an easy mechanism to generate data by the schema of any complexity.</li>
  <li><strong>Country-specific data providers</strong>: Provides data specific only for <a href="https://mimesis.name/api.html#builtin-data-providers">some countries</a>.</li>
</ul>

<p><br /></p>

<h2 id="mocking">Mocking</h2>

<p><a href="https://docs.python.org/3/library/unittest.mock.html"><strong>unittest.mock</strong></a> is a library from Python’s stdlib for mocking. 
It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used.</p>

<p><code class="language-plaintext highlighter-rouge">unittest.mock</code> provides a core <code class="language-plaintext highlighter-rouge">Mock</code> class removing the need to create a host of stubs throughout your test suite. 
After performing an action, you can make assertions about which methods / attributes were used and arguments they
were called with. You can also specify return values and set needed attributes in the normal way.</p>

<p><br /></p>

<p><a href="https://github.com/spulec/freezegun"><strong>FreezeGun</strong></a> is a library that allows your Python tests to travel through time
 by mocking the datetime module.</p>

<p>Once the decorator or context manager have been invoked, all calls to <code class="language-plaintext highlighter-rouge">datetime.datetime.now()</code>, 
<code class="language-plaintext highlighter-rouge">datetime.datetime.utcnow()</code>, <code class="language-plaintext highlighter-rouge">datetime.date.today()</code>, <code class="language-plaintext highlighter-rouge">time.time()</code>, <code class="language-plaintext highlighter-rouge">time.localtime()</code>, <code class="language-plaintext highlighter-rouge">time.gmtime()</code>, and <code class="language-plaintext highlighter-rouge">time.strftime()</code>
will return the time that has been frozen.</p>

<p><br /></p>

<p><a href="https://github.com/patrys/httmock"><strong>HTTPretty</strong></a> is an HTTP client mocking tool for Python - inspired by Fakeweb for Ruby.</p>

<p>Common use cases:</p>

<ul>
  <li>Test-driven development of API integrations</li>
  <li>Fake responses of external APIs</li>
  <li>Record and playback HTTP requests</li>
</ul>

<p><br /></p>

<h2 id="code-coverage">Code coverage</h2>

<p><a href="https://github.com/nedbat/coveragepy"><strong>Coverage.py</strong></a> measures code coverage, typically during test execution. It uses 
the code analysis tools and tracing hooks provided in the Python standard library to determine which lines are 
executable, and which have been executed.</p>

<p><br /></p>

<h2 id="object-factories">Object Factories</h2>

<p><a href="https://github.com/FactoryBoy/factory_boy"><strong>factory_boy</strong></a> is a fixtures replacement based on thoughtbot’s factory_bot.</p>

<p>As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures with easy-to-use 
factories for complex objects.</p>

<p><br /></p>

<h2 id="code-style">Code Style</h2>

<p><a href="https://github.com/wemake-services/wemake-python-styleguide"><strong>wemake-python-styleguide</strong></a> is is strictest and most 
opinionated python linter ever.</p>

<p>Goals of WPS:</p>

<ol>
  <li>Enforce <code class="language-plaintext highlighter-rouge">Python 3.6+</code> usage</li>
  <li>Significantly reduce complexity of your code and make it more maintainable</li>
  <li>Enforce “There should be one– and preferably only one –obvious way to do it” rule</li>
  <li>Create consistent coding and naming style</li>
</ol>

<p><br /></p>

<p><a href="https://github.com/PyCQA/pycodestyle"><strong>pycodestyle</strong></a> is a tool to check your Python code against some of the style 
conventions in PEP8.</p>

<p>Features:</p>

<ul>
  <li>Plugin architecture: Adding new checks is easy.</li>
  <li>Parseable output: Jump to error location in your editor.</li>
  <li>Small: Just one Python file, requires only <code class="language-plaintext highlighter-rouge">stdlib</code>. You can use just the <code class="language-plaintext highlighter-rouge">pycodestyle.py</code> file for this purpose.</li>
  <li>Comes with a comprehensive test suite.</li>
</ul>

<p><br /></p>

<p><a href="https://github.com/psf/black"><strong>Black</strong></a> is the uncompromising Python code formatter. By using it, you agree to cede
control over minutiae of hand-formatting. In return, <em>Black</em> gives you speed,
determinism, and freedom from <code class="language-plaintext highlighter-rouge">pycodestyle</code> nagging about formatting. You will save time
and mental energy for more important matters.</p>

<p><br /></p>

<p><a href="https://github.com/google/yapf"><strong>yapf</strong></a> is a formatter for Python files.</p>

<p>YAPF takes a different approach. It’s based off of <code class="language-plaintext highlighter-rouge">clang-format</code>, developed by Daniel Jasper. In essence, 
the algorithm takes the code and reformats it to the best formatting that conforms to the style guide, even if the 
original code didn’t violate the style guide. The idea is also similar to the ‘gofmt’ tool for the Go programming 
language: end all holy wars about formatting - if the whole codebase of a project is simply piped through YAPF 
whenever modifications are made, the style remains consistent throughout the project and there’s no point 
arguing about style in every code review.</p>

<p><br /></p>

<h2 id="typing">Typing</h2>

<p><a href="https://github.com/python/mypy"><strong>mypy</strong></a> is an optional static type checker for Python. You can add type 
hints (PEP 484) to your Python programs, and use <code class="language-plaintext highlighter-rouge">mypy</code> to type check them statically. Find bugs in your 
programs without even running them!</p>

<p>Here is a small example to whet your appetite (Python 3):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Iterator</span>

<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span>
    <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">1</span>
    <span class="k">while</span> <span class="n">a</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">a</span>
        <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="n">b</span><span class="p">,</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
</code></pre></div></div>

<p><br /></p>

<p><a href="https://github.com/facebook/pyre-check"><strong>Pyre</strong></a> is a performant type checker for Python compliant with PEP 484. 
Pyre can analyze codebases with millions of lines of code incrementally – providing instantaneous feedback to 
developers as they write code.</p>

<p>Pyre ships with Pysa, a security-focused static analysis tool we’ve built on top of Pyre that reasons about data flows 
in Python applications. Please refer to our documentation to get started with our security analysis.</p>

<p><br /></p>

<p><a href="https://github.com/python/typeshed"><strong>Typeshed</strong></a> contains external type annotations for the Python standard library 
and Python builtins, as well as third party packages as contributed by people external to those projects.</p>

<p><br /></p>

<p><a href="https://github.com/typeddjango/django-stubs"><strong>django-stubs</strong></a> contains type stubs and a custom <code class="language-plaintext highlighter-rouge">mypy</code> plugin to 
provide more precise static types and type inference for <code class="language-plaintext highlighter-rouge">Django</code> framework. Django uses some Python “magic” 
that makes having precise types for some code patterns problematic. This is why we need this project. The final goal 
is to be able to get precise types for most common patterns.</p>

<p><br /></p>

<p><a href="https://github.com/dry-python/returns"><strong>returns</strong></a> gonna make your functions return something meaningful, typed, and safe!</p>

<p>Features:</p>

<ul>
  <li>Brings functional programming to Python land</li>
  <li>Provides a bunch of primitives to write declarative business logic</li>
  <li>Enforces better architecture</li>
  <li>Fully typed with annotations and checked with <code class="language-plaintext highlighter-rouge">mypy</code>, PEP561 compatible</li>
  <li>Adds emulated Higher Kinded Types support</li>
  <li>Has a bunch of helpers for better composition</li>
  <li>Pythonic and pleasant to write and to read 🐍</li>
  <li>Support functions and coroutines, framework agnostic</li>
  <li>Easy to start: has lots of docs, tests, and tutorials</li>
</ul>

<p><br /></p>

<p>That’s it for now!</p>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[Experienced programmers understand perfectly well that in development they spend most of the time reading code and therefore they treat the process of writing code with the deepest trepidation.]]></summary></entry><entry><title type="html">The Idiomatic Comparison in Python</title><link href="https://isaak.dev/the-idiomatic-comparison-in-python" rel="alternate" type="text/html" title="The Idiomatic Comparison in Python" /><published>2020-07-08T00:00:00+00:00</published><updated>2020-07-08T00:00:00+00:00</updated><id>https://isaak.dev/the-idiomatic-comparison-in-python</id><content type="html" xml:base="https://isaak.dev/the-idiomatic-comparison-in-python"><![CDATA[<p>Some newbies in Python often improperly use the operators <code class="language-plaintext highlighter-rouge">is</code> and <code class="language-plaintext highlighter-rouge">==</code> without knowing how 
exactly they work and when to use each one. In this article, I’ll talk about the difference between 
them, and about the use cases of each one.</p>

<p>Spoiler: the main difference is that <code class="language-plaintext highlighter-rouge">is</code> compares IDs of objects to check if both the operands 
refer to the same object and cannot be overloaded, when <code class="language-plaintext highlighter-rouge">==</code> compares the values of the objects 
and can be overloaded using the magic method <code class="language-plaintext highlighter-rouge">__eq__</code>.</p>

<p>Have a look at this code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span> <span class="c1"># a.__eq__(b)
</span><span class="bp">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="ow">is</span> <span class="n">b</span>
<span class="bp">False</span>
</code></pre></div></div>

<p>That’s right  <code class="language-plaintext highlighter-rouge">a</code> is not <code class="language-plaintext highlighter-rouge">b</code>, and here is why:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a_id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="mi">4464140992</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">b_id</span> <span class="o">=</span> <span class="nb">id</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="mi">4465176960</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a_id</span> <span class="o">==</span> <span class="n">b_id</span>
<span class="bp">False</span>
</code></pre></div></div>

<h2 id="use-case-of-is">Use case of «is»</h2>

<p>Using operator <code class="language-plaintext highlighter-rouge">is</code> makes sense when you want to compare variable with a singleton-object, 
like <code class="language-plaintext highlighter-rouge">None</code>, <code class="language-plaintext highlighter-rouge">Ellipsis</code> and so on:</p>

<p>Good:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">some_object</span> <span class="ow">is</span> <span class="bp">Ellipsis</span><span class="p">:</span>
    <span class="n">do_some_stuff</span><span class="p">()</span>
</code></pre></div></div>

<p>Still, good:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">some_object</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">do_other_stuff</span><span class="p">()</span>
</code></pre></div></div>

<p>Bad (even it will work correctly, because <code class="language-plaintext highlighter-rouge">None</code> always equal to <code class="language-plaintext highlighter-rouge">None</code>):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">some_object</span> <span class="o">==</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">do_some_stuff</span><span class="p">()</span>
</code></pre></div></div>

<p>It’s better to write it like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="ow">not</span> <span class="n">some_object</span><span class="p">:</span>
    <span class="n">do_some_stuff</span><span class="p">()</span>
</code></pre></div></div>

<p>or like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">some_object</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">do_some_stuff</span><span class="p">()</span>
</code></pre></div></div>

<h2 id="use-case-of-">Use case of «==»</h2>

<p>Using operator <code class="language-plaintext highlighter-rouge">==</code> makes sense when you interested in comparing the values of objects:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">=</span> <span class="p">[]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span> <span class="c1"># [].__eq__([])
</span><span class="bp">True</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">c</span> <span class="o">=</span> <span class="s">'isaak'</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">d</span> <span class="o">=</span> <span class="s">'Isaak'</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">c</span> <span class="o">==</span> <span class="n">d</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span>
</code></pre></div></div>

<p>Keep in mind, that by default the magic method <code class="language-plaintext highlighter-rouge">__eq__</code> inherited from <code class="language-plaintext highlighter-rouge">object</code> compares 
IDs of objects (because it knows nothing about values).</p>

<p>You can read more about <code class="language-plaintext highlighter-rouge">__eq__</code> <a href="https://docs.python.org/3/reference/datamodel.html">here</a>.</p>

<h2 id="summary">Summary</h2>

<ul>
  <li>Use <code class="language-plaintext highlighter-rouge">is</code> when you compare variable with a singleton-object.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">==</code> when you want to compare the values of the objects.</li>
</ul>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[Let's talk about the fundamental difference between comparison operators.]]></summary></entry><entry><title type="html">Thoughts on naming variables, functions and methods</title><link href="https://isaak.dev/a-few-thoughts-about-naming" rel="alternate" type="text/html" title="Thoughts on naming variables, functions and methods" /><published>2020-07-06T00:00:00+00:00</published><updated>2020-07-06T00:00:00+00:00</updated><id>https://isaak.dev/a-few-thoughts-about-naming</id><content type="html" xml:base="https://isaak.dev/a-few-thoughts-about-naming"><![CDATA[<p>Properly naming variables, functions, methods, and classes is one of the most important attributes of elegant and clean code. It reflects the programmer’s intentions clearly, without leaving room for assumptions about what was meant.</p>

<p>In this article, we will discuss code that is the exact opposite of what we just described - code that was written carelessly or thoughtlessly. This article is a small confession, because like any other programmer, I have also written such code in the past (in fact, I still write bad code sometimes, although refactoring makes it much better). This is nothing terrible as long as we understand that we need to work on it.</p>

<p>This article is a translated version of my article from <a href="https://habr.com/ru/post/508238/">harb.com</a> so, 
if you know Russian then you can read the original version.</p>

<p>Let’s start.</p>

<h2 id="variables">Variables</h2>

<p>One of the most annoying types of variables are those that give a false impression of the nature of the data they store.</p>

<p>The <code class="language-plaintext highlighter-rouge">requests</code> library is extremely popular among Python developers, and if you have ever looked for anything 
related to <code class="language-plaintext highlighter-rouge">requests</code>, you must have come across something like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span>

<span class="n">req</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'https://api.example.org/endpoint'</span><span class="p">)</span>
<span class="n">req</span><span class="p">.</span><span class="n">json</span><span class="p">()</span>
</code></pre></div></div>

<p>Whenever I see this, I feel annoyed, not only because of the shortened name but also because the variable’s 
name does not match what is stored in it.</p>

<p>When you make a request (<code class="language-plaintext highlighter-rouge">requests.Request</code>), you get a response (<code class="language-plaintext highlighter-rouge">requests.Response</code>), 
so reflect this in your code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'https://api.example.org/endpoint'</span><span class="p">)</span>
<span class="n">response</span><span class="p">.</span><span class="n">json</span><span class="p">()</span>
</code></pre></div></div>

<p>Not <code class="language-plaintext highlighter-rouge">r</code>, not <code class="language-plaintext highlighter-rouge">res</code>, not <code class="language-plaintext highlighter-rouge">resp</code> and certainly not <code class="language-plaintext highlighter-rouge">req</code>, exactly <code class="language-plaintext highlighter-rouge">response</code>. <code class="language-plaintext highlighter-rouge">res</code>, <code class="language-plaintext highlighter-rouge">r</code>, <code class="language-plaintext highlighter-rouge">resp</code> – these are all 
variables whose contents can be understood only by looking at their definitions, and why jump to the definitions 
when you can initially give a suitable name?</p>

<p>Let’s look at another example, but now from Django:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users_list</span> <span class="o">=</span> <span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">filter</span><span class="p">(</span><span class="n">age__gte</span><span class="o">=</span><span class="mi">22</span><span class="p">)</span>
</code></pre></div></div>

<p>When you see <code class="language-plaintext highlighter-rouge">users_list</code> somewhere in the code, you quite rightly expect that you can do this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users_list</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">pk</span><span class="o">=</span><span class="mi">3</span><span class="p">))</span>
</code></pre></div></div>

<p>but no, you can’t do this, since <code class="language-plaintext highlighter-rouge">.filter()</code> returns a <code class="language-plaintext highlighter-rouge">QuerySet</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span>
<span class="c1"># ...
# ...
</span><span class="nb">AttributeError</span><span class="p">:</span> <span class="s">'QuerySet'</span> <span class="nb">object</span> <span class="n">has</span> <span class="n">no</span> <span class="n">attribute</span> <span class="s">'append'</span>
</code></pre></div></div>

<p>If it is very important for you to specify a suffix, then specify at least one that reflects the real situation:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users_queryset</span> <span class="o">=</span> <span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">()</span>
<span class="n">users_queryset</span><span class="p">.</span><span class="n">order_by</span><span class="p">(</span><span class="s">'-age'</span><span class="p">)</span>
</code></pre></div></div>

<p>also okay, because such abbreviations (<code class="language-plaintext highlighter-rouge">_qs</code>) are usual for Django:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users_qs</span> <span class="o">=</span> <span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">()</span>
</code></pre></div></div>

<p>If you really want to write exactly <code class="language-plaintext highlighter-rouge">_list</code>, then take care that the <code class="language-plaintext highlighter-rouge">list</code> really gets into the variable:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users_list</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">())</span>
</code></pre></div></div>

<p>Indicating a type of data that a variable contains is often a bad idea, especially when you deal with 
dynamic languages, such as Python. In cases when it is very necessary to note that the object is a 
container data type, it is enough to simply indicate the name of the variable in the plural:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">users</span> <span class="o">=</span> <span class="n">User</span><span class="p">.</span><span class="n">objects</span><span class="p">.</span><span class="nb">all</span><span class="p">()</span>
</code></pre></div></div>

<p>Consider another example:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">info_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s">'name'</span><span class="p">:</span> <span class="s">'Isaak'</span><span class="p">,</span> <span class="s">'age'</span><span class="p">:</span> <span class="mi">25</span><span class="p">}</span>
<span class="c1"># ...
# ... 
</span><span class="n">info_dict</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">info_dict</span><span class="p">)</span>
<span class="c1"># ...
# ...
</span></code></pre></div></div>

<p>You see a <code class="language-plaintext highlighter-rouge">dict</code> and you might want to do this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">info_dict</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
    <span class="k">print</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
</code></pre></div></div>

<p>Instead, you’ll get an exception, because you were misled, and you will understand this only 
if you go to the definition of the variable and read the entire code from top to bottom,
right down to the section from which you started the jump — this is the price of such variables.</p>

<p>Thus, when you indicate in the variable name the type of data stored in it, you are essentially a 
guarantee that this variable must contain the specified data type at any time during the execution of the program. 
Why should you take this responsibility if it is the direct responsibility of the interpreter or compiler? 
You shouldn’t! Better to spend time thinking of a good variable name than trying to figure out why the 
variables do not behave as you expect.</p>

<p>In the example above, the choice of the name of a variable is rather bad, and you could give a 
name that more accurately expresses the context (no need to be afraid to use the domain-specific names),
but even in this case, you could make this code better:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">info_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s">'name'</span><span class="p">:</span> <span class="s">'Isaak'</span><span class="p">,</span> <span class="s">'age'</span><span class="p">:</span> <span class="mi">25</span><span class="p">}</span>
<span class="c1"># ...
# ... 
</span><span class="n">info_keys</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">info_dict</span><span class="p">)</span>
<span class="c1"># ...
# ...
</span></code></pre></div></div>

<p>or even like this, which is more idiomatic:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">info_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s">'name'</span><span class="p">:</span> <span class="s">'Isaak'</span><span class="p">,</span> <span class="s">'age'</span><span class="p">:</span> <span class="mi">25</span><span class="p">}</span>
<span class="c1"># ...
# ... 
</span><span class="n">info_keys</span> <span class="o">=</span> <span class="n">info_dict</span><span class="p">.</span><span class="n">keys</span><span class="p">()</span>
<span class="c1"># ...
# ...
</span></code></pre></div></div>

<p>Another type of annoying variable is ones with a shortened name.</p>

<p>Let’s go back to <code class="language-plaintext highlighter-rouge">requests</code> and consider this code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">s</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">Session</span><span class="p">()</span>
<span class="c1"># ...
# ... 
</span><span class="n">s</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>

<p>This is an example of an unnecessary shortening for a variable name. 
This is a terrible practice, and its horror becomes even more apparent when such code 
takes up more than 10-15 lines of code.</p>

<p>It is much better to write as is, namely:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">session</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">Session</span><span class="p">()</span>
<span class="c1"># ...
# ...
</span><span class="n">session</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'https://api.example.org/endpoint'</span><span class="p">)</span>
<span class="c1"># ...
# ...
</span><span class="n">session</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div></div>

<p>or</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="n">requests</span><span class="p">.</span><span class="n">Session</span><span class="p">()</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
    <span class="n">session</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'https://api.example.org/endpoint'</span><span class="p">)</span>
</code></pre></div></div>

<p>You may argue that this is a more verbose option, but I will answer you that it pays off when 
you read the code and immediately understand that <code class="language-plaintext highlighter-rouge">session</code> is a <code class="language-plaintext highlighter-rouge">Session</code>.</p>

<p>Will you understand it by variable <code class="language-plaintext highlighter-rouge">s</code> without looking at its definition?</p>

<h2 id="methods">Methods</h2>

<p>Smart naming of functions and methods is something that comes only with experience in designing an API,
and therefore you can often find cases where methods do not behave as you expect.</p>

<p>Consider an example:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">person</span> <span class="o">=</span> <span class="n">Person</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">person</span><span class="p">.</span><span class="n">has_publications</span><span class="p">()</span>
<span class="p">[</span><span class="s">'Post 1'</span><span class="p">,</span> <span class="s">'Post 2'</span><span class="p">,</span> <span class="s">'Post 3'</span><span class="p">]</span>
</code></pre></div></div>

<p>We expressed a very clear-cut question in our code: “Does this person have publications?”, 
but what kind of answer did we get? Did we ask for a list of publications of a person?</p>

<p>The name of this method implies that the return value must be of Boolean type, namely <code class="language-plaintext highlighter-rouge">True</code> or <code class="language-plaintext highlighter-rouge">False</code>:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">person</span> <span class="o">=</span> <span class="n">Person</span><span class="p">()</span>
<span class="o">&gt;&gt;&gt;</span> <span class="n">person</span><span class="p">.</span><span class="n">has_publications</span><span class="p">()</span>
<span class="bp">True</span>
</code></pre></div></div>

<p>We can use a more appropriate method name for getting publications:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">person</span><span class="p">.</span><span class="n">get_publications</span><span class="p">()</span>
<span class="p">[</span><span class="s">'Post 1'</span><span class="p">,</span> <span class="s">'Post 2'</span><span class="p">,</span> <span class="s">'Post 3'</span><span class="p">]</span>
</code></pre></div></div>

<p>or</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="n">person</span><span class="p">.</span><span class="n">publications</span><span class="p">()</span>
<span class="p">[</span><span class="s">'Post 1'</span><span class="p">,</span> <span class="s">'Post 2'</span><span class="p">,</span> <span class="s">'Post 3'</span><span class="p">]</span>
</code></pre></div></div>

<p>We often like to call programming a creative activity, and it really is. 
However, if you write not readable code, and then justify it with “creativity”, then I have bad news for you.</p>

<h2 id="further-reading">Further reading</h2>

<p>I’m leaving this  list of outstanding relevant literature written by well-known 
professionals in the field for further study of the issue:</p>

<ol>
  <li>Robert Martin — <a href="https://amzn.to/2VLWw7S">Clean Architecture</a></li>
  <li>Martin Fowler — <a href="https://bit.ly/2NTEaOa">Refactoring: Improving the Design of Existing Code</a></li>
</ol>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[Properly naming variables, functions, methods, and classes is one of the most important attributes of elegant and clean code.]]></summary></entry><entry><title type="html">A Teeny-Tiny Note About Comments and Dead Code</title><link href="https://isaak.dev/note-about-comments-and-dead-code" rel="alternate" type="text/html" title="A Teeny-Tiny Note About Comments and Dead Code" /><published>2020-07-05T00:00:00+00:00</published><updated>2020-07-05T00:00:00+00:00</updated><id>https://isaak.dev/note-about-comments-and-dead-code</id><content type="html" xml:base="https://isaak.dev/note-about-comments-and-dead-code"><![CDATA[<p>Comments are something that can both: ruin your code and make it better.</p>

<p>A good comment takes time to think and write, and therefore most often we all come across 
disgusting comments that are nothing but a piece of visual garbage.</p>

<p>Let’s consider a small example from JavaScript:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Remove first five letters</span>
<span class="kd">const</span> <span class="nx">errorCode</span> <span class="o">=</span> <span class="nx">errorText</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</code></pre></div></div>

<p>The first thought that flashes in your head when you see this is “Thank you, cap!”. 
Why should we describe things that are already clear without comment? Why should we duplicate the information 
that the code already tells us?</p>

<p>This distinguishes a good comment from a bad one - a good comment makes you feel grateful for the 
developer who wrote it when a bad comment just annoys you as hell.</p>

<p>Let’s try to make this comment a little useful:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Remove "net::" from the error text</span>
<span class="kd">const</span> <span class="nx">errorCode</span> <span class="o">=</span> <span class="nx">errorText</span><span class="p">.</span><span class="nx">substr</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</code></pre></div></div>

<p>Better yet, resort to a more declarative approach and opt-out the comment:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">errorCode</span> <span class="o">=</span> <span class="nx">errorText</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="dl">'</span><span class="s1">net::</span><span class="dl">'</span><span class="p">,</span> <span class="dl">''</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="dead-code">Dead code</h2>

<p>Dead code, perhaps, is much more annoying than useless comments, since you also have to figure out was the code commented out 
temporarily (to debug some parts of the system or something), or did the developer just forget to delete it?</p>

<p>Be that as it may, dead code has no place in the modules and it should be deleted! If it suddenly turns out that 
this was something important, then you can just roll back to the correct version (unless, of course, you are 
something like an Amish programmer that does not use the version control system).</p>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[A good comment takes time to think and write, and therefore most often we all come across disgusting comments that are nothing but a piece of visual garbage.]]></summary></entry><entry><title type="html">The Beginning of The Way</title><link href="https://isaak.dev/the-beginning-of-the-way" rel="alternate" type="text/html" title="The Beginning of The Way" /><published>2020-07-04T00:00:00+00:00</published><updated>2020-07-04T00:00:00+00:00</updated><id>https://isaak.dev/the-beginning-of-the-way</id><content type="html" xml:base="https://isaak.dev/the-beginning-of-the-way"><![CDATA[<p>As we all know, the best way to learn new things is by teaching others 
and this blog is my way to learn new things.</p>

<p>I will mainly write on this blog about software development in terms of my 
main programming languages, i.e <code class="language-plaintext highlighter-rouge">Python</code> and <code class="language-plaintext highlighter-rouge">JavaScript</code>.</p>

<p>Also, I’m going to write here about the programming languages and technologies I learn.
At this moment my main interest is <code class="language-plaintext highlighter-rouge">Rust</code>, <code class="language-plaintext highlighter-rouge">Erlang/Elixir</code> and <code class="language-plaintext highlighter-rouge">Clojure</code>.</p>

<p>So, that’s it.</p>

<p>You can read more about me <a href="https://isaak.dev/about">here</a>.</p>

<p>P.S I’m not a native English speaker, so I hope my readers will treat my 
grammar mistakes with patience and understanding.</p>]]></content><author><name>Isaak Uchakaev</name></author><summary type="html"><![CDATA[As we all know, the best way to learn new things is by teaching others and this blog is my way to learn new things.]]></summary></entry></feed>