<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sergey Piskunov</title>
    <description>The latest articles on DEV Community by Sergey Piskunov (@0x808080).</description>
    <link>https://dev.to/0x808080</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F980824%2Fef7d9861-e703-4254-a1e6-03939b03f8be.JPG</url>
      <title>DEV Community: Sergey Piskunov</title>
      <link>https://dev.to/0x808080</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/0x808080"/>
    <language>en</language>
    <item>
      <title>N+1 variations of a Singleton in Python</title>
      <dc:creator>Sergey Piskunov</dc:creator>
      <pubDate>Mon, 07 Aug 2023 18:08:55 +0000</pubDate>
      <link>https://dev.to/0x808080/n1-variations-of-a-singleton-in-python-3j4m</link>
      <guid>https://dev.to/0x808080/n1-variations-of-a-singleton-in-python-3j4m</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;There are cases when we need to have one and only one instance of a particular class in our program. We may want this instance to encapsulate state and logic, accessible from multiple locations within the application. Such scenarios are ideal for object that consume significant resources and serve as a central access point to specific resources. Examples include database connections, logging helpers, and application settings. The Singleton is the creational design pattern that shows us how to create such an object. Let's see how many ways we may implement a Singleton pattern (and its variations) in Python and try to analyze the pros and cons of each.&lt;/p&gt;

&lt;p&gt;When discussing the concept of "one and only one instance" it is crucial to consider the specific boundaries of that uniqueness. These boundaries are commonly referred to as namespaces or scopes.&lt;/p&gt;

&lt;p&gt;The logic behind the Singleton pattern includes the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defining a namespace to hold an instance.&lt;/li&gt;
&lt;li&gt;Upon an object creation request, check if an instance already exists within the chosen namespace. If it does, return the existing instance; otherwise, create a new instance and save it within that namespace.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Python, namespaces can be defined at different levels, including a module, a function, or a class. Therefore, the actual implementations of this pattern will be based on these options, depending on where the unique instance is intended to be stored.&lt;/p&gt;

&lt;p&gt;Let's assume we have the following class, which we need to turn into a Singleton:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# example.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""This is a helper class providing a way to send requests 
    to some third-party service. We want to use it across 
    the whole application as the single access point to that 
    third-party service"""&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Let's assume that the initialization phase of this 
&lt;/span&gt;        &lt;span class="c1"&gt;# helper includes some hard work in creating the 
&lt;/span&gt;        &lt;span class="c1"&gt;# connection to the particular server. 
&lt;/span&gt;        &lt;span class="c1"&gt;# To avoid repeating this work, it holds that connection 
&lt;/span&gt;        &lt;span class="c1"&gt;# in the instance attribute for reusing in the future.
&lt;/span&gt;        &lt;span class="c1"&gt;# Let's keep our example as simple as this:
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"connection to the &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

        &lt;span class="c1"&gt;# Let's print a notification to indicate that our 
&lt;/span&gt;        &lt;span class="c1"&gt;# 'connection' was established by the particular 
&lt;/span&gt;        &lt;span class="c1"&gt;# Server instance
&lt;/span&gt;        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; connected to the &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Instead of making real requests somewhere, 
&lt;/span&gt;        &lt;span class="c1"&gt;# let's just print a notification.
&lt;/span&gt;        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; sent request via &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Python, objects are considered the same if they have the same identifier. However, we will not only compare the IDs but also check the actual state of our instances by calling &lt;code&gt;instance.ping()&lt;/code&gt; and observing the actual server being requested.&lt;/p&gt;

&lt;p&gt;Let's use the Python shell to run our examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from example import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
140262246251248 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140262246251248 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the helper class establishes the connection right after initialization. The log messages contain instance IDs, which indicate the exact instance that established the connection and performed the request.&lt;/p&gt;

&lt;p&gt;Let's begin with the simplest way to convert our Server class into a Singleton.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module-level variable
&lt;/h2&gt;

&lt;p&gt;In Python, when a module is imported, its contents are executed only once, and subsequent imports of the same module will refer to the already loaded module object. This behavior ensures that the module's variables, functions, and classes are shared across different parts of the code, providing a singleton-like behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# module_level_variable.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"test.server"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from module_level_variable import srv
140138551301488 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140138551301488 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from module_level_variable import srv
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140138551301488 sent request via connection to the test.server

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

&lt;/div&gt;



&lt;p&gt;Despite re-importing, we still have the same initialized instance sending requests already. &lt;/p&gt;

&lt;p&gt;That is indeed the most straightforward implementation, where no modification of the target class is needed. Python itself provides accessibility and state persistence for free. However, it's worth noting that the connection occurs right after the class is first imported, which can be disadvantageous in some cases. We may prefer initializing the instance at a specific time rather than immediately after importing.&lt;/p&gt;

&lt;p&gt;Now, let's explore how we can eliminate this initialization disadvantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module-level variable with instance getter
&lt;/h2&gt;

&lt;p&gt;We may initialize instances when needed using a module-level function responsible for returning either a new or already instantiated object from the global namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# module_level_instance_getter.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;


&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from module_level_instance_getter import get_instance
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139961814546704 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139961814546704 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv2 &lt;span class="o"&gt;=&lt;/span&gt; get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv2.ping&lt;span class="o"&gt;()&lt;/span&gt;
139961814546704 sent request via connection to the test.server

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

&lt;/div&gt;



&lt;p&gt;We can update this instance getter to work with any class passed as a parameter. That will allow you to turn any class into a singleton by keeping them in a global mapping and storing created singletons in the global variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# module_level_multiple_instances_getter.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;


&lt;span class="n"&gt;singletons&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_singleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;singletons&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;singletons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;singletons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;singletons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from module_level_multiple_instances_getter import get_singleton, Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; get_singleton&lt;span class="o"&gt;(&lt;/span&gt;Server, &lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139938106238832 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; get_singleton&lt;span class="o"&gt;(&lt;/span&gt;Server, &lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139938106238832 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
139938106238832 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One may ask why not make the &lt;code&gt;get_instance&lt;/code&gt; a class method. Let's see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Class-method instance getter
&lt;/h2&gt;

&lt;p&gt;We can use the class namespace as a scope containing the instance. Let's add the &lt;code&gt;get_server&lt;/code&gt; class method to our helper class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# class_method_getter.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

    &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from class_method_getter import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server.get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139953073616112 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139953073616112 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; Server.get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
139953073616112 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how easily we can break this (and the previous) implementation by omitting the &lt;code&gt;get_instance&lt;/code&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_3 &lt;span class="o"&gt;=&lt;/span&gt; Server.get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139953073616112 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_3.ping&lt;span class="o"&gt;()&lt;/span&gt;
139953073616112 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_4 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139953073617168 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_4.ping&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a hack allowing us to create a single entrypoint for instance creation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module-level instance getter with a nested class
&lt;/h2&gt;

&lt;p&gt;Python allows us to enclose the whole class definition within a particular function which may be a single entrypoint for getting the class instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# module_level_getter_nested_class.py
&lt;/span&gt;
&lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;        

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from module_level_getter_nested_class import get_instance
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
140111140043504 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140111140043504 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; get_instance&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
140111140043504 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While the solution works, it is not commonly used due to its inflexibility. Furthermore, the use of those getters is considered non-Pythonic. The tight coupling of Singleton-related logic with the target class appears to break the Single Responsibility Principle. Fortunately, there are better approaches to address these issues and improve the implementation of the Singleton pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Class decorator
&lt;/h2&gt;

&lt;p&gt;The multiparadigm nature of Python enables us to create class decorators that can encapsulate the Singleton-related behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# class_decorator.py
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;singleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;singleton&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from class_decorator import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
140568956844784 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140568956844784 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
140568956844784 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While we achieved cleaner, more readable, and untangled code, we may encounter issues with child classes. To ensure a more robust approach, let's explore other solutions that can effectively handle inheritance and child classes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base class
&lt;/h2&gt;

&lt;p&gt;We can store the instance within a class variable and implement the Singleton-related logic in the &lt;code&gt;__new__&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# base_class.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from base_class import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139871502953360 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139871502953360 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139871502953360 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
139871502953360 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting subclassed Server class can be further subclassed if needed, and these subclasses will continue to act as singletons. However, this solution has an issue: the 'connected to the test.server' log message appears twice. This approach does not allow us to run initialization lazily, only during the first call. That may be an issue for resource-heavy initialization. &lt;br&gt;
Indeed, there is room for improvement. Let's continue exploring more sophisticated approaches to implement the Singleton pattern.&lt;/p&gt;
&lt;h2&gt;
  
  
  Metaclass
&lt;/h2&gt;

&lt;p&gt;We instantiate our Singleton class from the &lt;code&gt;type&lt;/code&gt; in this approach, which is required to achieve proper metaclass behavior in Python. In the case of a metaclass, the &lt;code&gt;__call__&lt;/code&gt; method is called first, making it an excellent place to intercept instance creation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# metaclass.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instance&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Singleton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from metaclass import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
140421527038288 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140421527038288 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv2 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv2.ping&lt;span class="o"&gt;()&lt;/span&gt;
140421527038288 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution looks like the most Pythonic way to implement a Singleton. It is readable, pluggable, works for subclassed objects, and may be a good choice if not for one but.&lt;/p&gt;

&lt;p&gt;In the real application we may want to have connectors to multiple servers, which of them acting as independent singleton.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from metaclass import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
140654371744080 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140654371744080 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"second.test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
140654371744080 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
140654371744080 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the &lt;code&gt;srv&lt;/code&gt; instance's connection gets "overridden" by the newly created instance. This occurs because of the primitive-type variable &lt;code&gt;_instance&lt;/code&gt;, which can hold only one instance at a time. Let's see how we can deal with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiton
&lt;/h2&gt;

&lt;p&gt;Multiton is a variation of the Singleton pattern where we can store multiple instances based on certain criteria. In our case, we can use a dictionary with a key consisting of the class name and class arguments to resolve the issue encountered in the previous section effectively.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# multiton.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Multiton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# This implementation of a unique key may be sensitive 
&lt;/span&gt;        &lt;span class="c1"&gt;# to complex objects passed as parameters. Feel free to 
&lt;/span&gt;        &lt;span class="c1"&gt;# override this method for the target class to fit 
&lt;/span&gt;        &lt;span class="c1"&gt;# your specific use-case.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Multiton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python Shell test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; from multiton import Server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139800681970704 connected to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139800681970704 sent request via connection to the test.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2 &lt;span class="o"&gt;=&lt;/span&gt; Server&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"test.second.server"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
139800681969888 connected to the test.second.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv_2.ping&lt;span class="o"&gt;()&lt;/span&gt;
139800681969888 sent request via connection to the test.second.server
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; srv.ping&lt;span class="o"&gt;()&lt;/span&gt;
139800681970704 sent request via connection to the test.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It appears that we have found the most effective implementation so far, but let's take a moment to consider a different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monostate
&lt;/h2&gt;

&lt;p&gt;We have been trying to reuse the same instance all this time, but Alex Martelli notes that we should focus on the shared state and behavior rather than the shared identity. He proposed using the Monostate pattern instead, where there may be multiple instances, but they share the same &lt;code&gt;__dict__&lt;/code&gt; special method's contents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# monostate.py
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Monostate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_shared_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__dict__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_shared_state&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Monostate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alex actually calls it a nonpattern because of a lack of evidence of widespread usage. It is a bit less intuitive than the classic Singleton approach, and the actual implementation may differ according to the use case. However, I think there is room for such an approach as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thread safety
&lt;/h2&gt;

&lt;p&gt;So far, we have achieved a robust implementation of the Singleton (Multiton) pattern using a metaclass. However, it appears that our implementation may misbehave in a multithreaded context. When object creation occurs within code shared by multiple threads, there can be a race condition. One thread might start instantiating an object, and then another thread takes control. Since the object is not yet fully created, the second thread starts creating it as well. In the following test, this issue was reproduced with the help of the deliberately slowed-down &lt;code&gt;__init__&lt;/code&gt; method. That may be the case for a heavy initializing logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# thread_test.py
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Monostate&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;result_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_instance&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;result_set&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;create_instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Created &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; instance(s):"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result_set&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Created 5 instance&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;:
&amp;lt;__main__.Server object at 0x7f2f8d72b8b0&amp;gt;
&amp;lt;__main__.Server object at 0x7f2f8d72ba30&amp;gt;
&amp;lt;__main__.Server object at 0x7f2f8d72b7f0&amp;gt;
&amp;lt;__main__.Server object at 0x7f2f8d72b730&amp;gt;
&amp;lt;__main__.Server object at 0x7f2f8d72b970&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the use case, we should decide whether to make our instance unique within each thread or unique across all threads. &lt;/p&gt;

&lt;h3&gt;
  
  
  Thread confined Multiton
&lt;/h3&gt;

&lt;p&gt;By utilizing this approach, we can associate the state with a particular thread. However, it's crucial to understand that this would no longer be a Singleton pattern at the global application level. Instead, each thread will have its unique instance of the object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# thread_confined.py
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;threading&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Multiton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_ensure_local_namespace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"_instances"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# This implementation of a unique key may be sensitive 
&lt;/span&gt;        &lt;span class="c1"&gt;# to complex objects passed as parameters. Feel free to 
&lt;/span&gt;        &lt;span class="c1"&gt;# override this method for the target class to fit 
&lt;/span&gt;        &lt;span class="c1"&gt;# your specific use-case.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_ensure_local_namespace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Thread safe Multiton
&lt;/h3&gt;

&lt;p&gt;To avoid race conditions, we must lock access to the shared &lt;code&gt;_instances&lt;/code&gt; dictionary while an instance is being instantiated. That may be easily achieved with the Lock object from the Python standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# thread_safe.py
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;threading&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Multiton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;_lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# This implementation of a unique key may be sensitive 
&lt;/span&gt;        &lt;span class="c1"&gt;# to complex objects passed as parameters. Feel free to 
&lt;/span&gt;        &lt;span class="c1"&gt;# override this method for the target class to fit 
&lt;/span&gt;        &lt;span class="c1"&gt;# your specific use-case.
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;instance_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_generate_instance_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Double-checked locking technique
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance_key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance_key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;instance_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_instances&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;instance_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;metaclass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Multiton&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;""" The actual implementation is in the Intro section """&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Created 1 instance&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt;:
&amp;lt;__main__.Server object at 0x7f0c6e16b730&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One may ask why &lt;code&gt;if instance_key not in cls._instances&lt;/code&gt; is called twice. Technically, it would be sufficient to make that check once after the lock is acquired. However, the case when this check results in &lt;code&gt;True&lt;/code&gt; will occur for the very first call only. All subsequent calls will result in &lt;code&gt;False&lt;/code&gt; indicating that the lock was acquired unnecessarily. Acquiring locks unnecessarily in a class/method can lead to slow code that is hard to identify, so it's crucial to acquire locks only when necessary to avoid performance issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Epilogue
&lt;/h2&gt;

&lt;p&gt;As we are aware, there is no universal solution, and nearly every approach has its limitations and disadvantages. Some articles even label the Singleton as an antipattern. Among the concerns, such as "difficult to comprehend," "challenging to read," and "violates the Single Responsibility Principle," one particular concern holds significant meaning. The constraint of utilizing only a single instance may complicate testing in scenarios where we genuinely require multiple tests against various states of that instance. However, this problem can be alleviated by structuring the application in a way that allows external injection of the instance. During regular operations, the block of code can utilize the &lt;code&gt;Server(metaclass=Multiton)&lt;/code&gt; instance, yet during tests, the &lt;code&gt;Server()&lt;/code&gt; instance can be externally injected.&lt;/p&gt;

&lt;p&gt;We must also bear in mind that, in certain cases, the namespace housing unique instances could be overwritten by invoking &lt;code&gt;importlib.reload(module_name)&lt;/code&gt;. This action would result in the re-instantiation of instances.&lt;/p&gt;

&lt;p&gt;Additionally, depending on the specific implementation, extra steps might be necessary to dispose of instantiated singletons. Even if we no longer require those instances, the scope retaining references to our singletons could hinder the garbage collector from eliminating them.&lt;/p&gt;

&lt;p&gt;In the context of simple projects or prototypes, one might resort to module-level variables for maintaining unique instances. Nevertheless, a metaclass approach is preferable for more intricate scenarios, particularly when lazy evaluation is imperative. When crafting a common library without a clear vision of its usage, opting for a thread-safe approach is advisable.&lt;/p&gt;

&lt;p&gt;Anyway, despite of added complexity and risks, it is better to understand the idea behind the Singleton pattern. Its ability to provide a single access point to some resource with lazy instantiation outweighs its drawbacks, at least for languages like Python.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/library/view/learning-python-design/9781785888038/"&gt;Chetan Giridhar. 2016. Learning Python Design Patterns&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.manning.com/books/software-mistakes-and-tradeoffs"&gt;Lelek, Tomasz. Skeet, John. 2021. Software Mistakes and Tradeoffs&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://refactoring.guru/design-patterns/book"&gt;Shvets, Alexander. 2022. Dive Into Design Patterns&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="http://www.aleax.it/5ep.html"&gt;Five Easy Pieces: Simple Python Non-Patterns&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>python</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Model Thinking course from the software engineer’s perspective</title>
      <dc:creator>Sergey Piskunov</dc:creator>
      <pubDate>Sat, 04 Mar 2023 20:30:28 +0000</pubDate>
      <link>https://dev.to/0x808080/model-thinking-course-from-the-software-engineers-perspective-5gon</link>
      <guid>https://dev.to/0x808080/model-thinking-course-from-the-software-engineers-perspective-5gon</guid>
      <description>&lt;p&gt;I want to give a review on the "Model Thinking" course, which I have recently completed using Coursera platform. Although this 8-week online course from Michigan University aims to make us better citizens of the world and decision-makers in general, I will share my thoughts about how that course's material may be applied to software engineering. I'm going to  discuss several course sections that were the most relevant for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we model?
&lt;/h2&gt;

&lt;p&gt;As the first quote from this course's material, I'd like to put this one: &lt;em&gt;"Models are the new Lingua Franca which allow people from different domains to communicate their ideas simply and clearly."&lt;/em&gt;. We all know from Domain Driven Design how crucial for a software project is to have a ubiquitous language between engineers and non-technical colleagues. Enriching our documentation with models makes communication between team members even more effective.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"We don't want to let the models tell us what to do. We want the models to help us make better choices. Smart people use both models and experience and not just blindly use models.".&lt;/em&gt; Models are not a silver bullet, though; we should understand their applications and restrictions, making them just yet another tool but not a replacement for common sense and experience.&lt;/p&gt;

&lt;p&gt;One of the most widespread examples of using models in a software engineer's routine is explaining the complexity of algorithms. We usually do not say "The Bubble Sort" is slow, but the "Merge Sort" is faster because each person has their own understanding of fast and slow. We say the "Bubble Sort" has O(n^2) time complexity, and the "Merge Sort" has the O(n log n). So during decision-making, we operate not with our emotions and feelings about the speed of algorithms, but we use their mathematical models. That gives us a fair performance comparison and understanding of possible applications of those algorithms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sorting and peer effects.
&lt;/h2&gt;

&lt;p&gt;Here we can find an exciting model of social behavior, which may explain, for example, how we adopt new technologies within the industry (or new ideas within a team). &lt;em&gt;"Granovetter's Model - The tail wags the dog. The people at the tail of the normal distribution are extremists, who sometimes drive what happens because of the chain reaction of thresholds of other people. Collective action is more likely if there are lower thresholds (the "tail" which leads to a cascade effect of "wagging the dog") and there is more variation in thresholds (which increases the probability of the chain reaction)."&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Standing Ovation Model - Granovetter's model, in which the cascade effect is amplified by "expert" opinion, the opinion of a friend, a celebrity, or other influencers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggregation.
&lt;/h2&gt;

&lt;p&gt;This section explains a lot of concepts, which a regular software developer may face in a day-to-day work, like the Bell Curve, Standard Deviation, and Mean. We may often see those terms in performance-testing reports or monitoring dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision models.
&lt;/h2&gt;

&lt;p&gt;I have found this section useful as it gives us decision-making tools to deal with complex subjects with multiple characteristics - "Multi-Criterion Choice Models". Imagine you must choose a framework or library among a dozen options. While each candidate has a dozen of aspects. A comparison table may be the right tool for that, but you may need to learn how to make the results of such comparison even more expressive using weights and distances. Also, one of the essential things in this section is a general recap on the Probabilistic Theory, Decision Trees — a crucial grounding for every engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models of people. Thinking Electrons.
&lt;/h2&gt;

&lt;p&gt;This section may not give us concrete technical advice, but it sheds light on how people behave. The authors show examples of people's rational, irrational, and rule-based actions and different types of biases. That may help us to understand people better and thus to be better team players.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linear models.
&lt;/h2&gt;

&lt;p&gt;The Linear Models section gives us many insights not only about reading the output of some types of statistical analysis (for example, Regression Output), but about ways to explain the raw data you have. For example, you may find that the more execution threads do you add, the fastest your code becomes. You may assume that the speed of your code linearly depends on the amount of resources you have, and you may plan your server's capacities according to that assumption. But one of the crucial caveats here is to be careful about extrapolating your linear data outside the data range. At some point, you may notice that adding more X does not give you more Y.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Correlation is not causation"&lt;/em&gt; is also important to remember during any historical data analysis and attempts to predict the future using that data. The authors give you a wise idea that to optimize your system even more, you might need a so-called "New Reality". To have better results, you are just building the new system instead of optimizing an old one. "The New Reality - is moving outside the box, explained by linear models and coefficients to the new system. Instead of endless optimizing of the SQL queries, try to re-align your data so that it may fit into the NoSQL paradigm."&lt;/p&gt;

&lt;h2&gt;
  
  
  Economic growth.
&lt;/h2&gt;

&lt;p&gt;What kind of economic-related knowledge may we reuse in our software engineering paths? Our engineering paths consist not only of technologies we know now but of how we evolve as professionals and grow. That growth has much more in common with economic growth than you may think. Assuming that our skill set is a kind of our personal GDP, we may apply the economic growth models to ourselves! The basic economic growth model suggests that Sustainable growth requires innovation. Let me quote the excerpt: &lt;em&gt;"You can't just do more. At some point, the rate at which things fall off and the rate at which things increase is just going to even out. If you look at the data on what makes for really successful people, people who are very successful in their careers continue to learn."&lt;/em&gt;. That is especially important in the age of replacing some jobs with Machine Learning systems and other types of automation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Growth requires creative destruction".&lt;/em&gt; Another example is the evolution of programming languages. I'm not going to start the Holy War related to the specific languages, but I want to say, that there is a mathematical model, showing us that, at some point, it is better to create (or adopt) the new fancy programming language instead of cluttering a 20-year-old one with new concepts, while also trying not to break backward compatibility and its idiomatic style.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diversity and innovation.
&lt;/h2&gt;

&lt;p&gt;This section describes a thing we face almost every day at our work. The "No Free Lunch Theorem". I could not find words better than the author's explanation - &lt;em&gt;"No Free Lunch Theorem tells us that no single heuristic is always effective. A heuristic that works great for one problem class may be ineffective for another problem type... All algorithms that search the same number of points with the goal of locating the maximum value of a function defined on a finite set perform exactly the same when averaged over all possible functions.&lt;/em&gt;" That may come in handy during the design and optimization of algorithms/business logic. This section has some additional problem-solving tip as well - &lt;em&gt;"When we go about solving problems, the first thing we do is we encode them. We have some representation of the problem. That representation determines how hard the problem will be."&lt;/em&gt;. That is why it is not a good idea to start writing code immediately after reading the task description. It's better to invest decent time in design and preparation, pseudo-coding, and leave the coding itself as the less important routine stage. We may find in this section a mathematical proof of why teams are better at problem-solving than individuals - because of diversity, perspectives, heuristics, and recombination of those new ideas. You'll always uphold a command work after hearing that explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Networks.
&lt;/h2&gt;

&lt;p&gt;This is again something one may have studied in college, but worth repeating. Networks and graphs are literally everywhere, from the computer network itself and distributed systems within those networks to the object inheritance and dependency graphs in the source code. The McCabe code complexity analysis, graph databases, and graph query languages are also based on the theory explained in this section.&lt;/p&gt;

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

&lt;p&gt;I have reviewed a little more than half of the sections of the "Model Thinking" course—only those I have found the most applicable to my personal path of a software engineer. However, your list of favorite concepts may differ because the knowledge you'll get after taking this course is rather a meta-knowledge that may be applicable to a wide variety of cases in your life. So, I encourage not only software engineers, but all to take that course.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.coursera.org/learn/model-thinking" rel="noopener noreferrer"&gt;Coursera "Model Thinking" course&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Source code structure checklist</title>
      <dc:creator>Sergey Piskunov</dc:creator>
      <pubDate>Mon, 02 Jan 2023 18:50:02 +0000</pubDate>
      <link>https://dev.to/0x808080/source-code-structure-checklist-a8f</link>
      <guid>https://dev.to/0x808080/source-code-structure-checklist-a8f</guid>
      <description>&lt;p&gt;This is my checklist for a source code structure. Of course, there is no silver bullet and different domains/technologies/languages have their specific requirements and limitations. So, here is the language-agnostic and domain-agnostic set of questions I usually ask myself while assessing the existing code base and before creating a new one. I do not try to get all of those boxes checked altogether, but I should understand why any of them is unchecked and determine whether it is a “red flag” for the particular project.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Does the source code tell you “what does the service do” instead of “which framework or library it is based on”?
&lt;/h2&gt;

&lt;p&gt;This will check how easy it is to open the code and quickly find a place for a new feature, make a bug fix or check how the particular part of the business logic works. &lt;/p&gt;

&lt;p&gt;We are used to read the code much more often than to write it. So we need to squeeze the maximum out of our programming language’s expressiveness. I’m talking not only about the proper names for variables, classes etc., but about the structure of files and directories as well. We often build our projects on top of a certain framework which imposes a structure to the entire project. Switching to the new framework often leads to re-writing the whole code base. Steve McConnell in his book &lt;a href="https://www.oreilly.com/library/view/code-complete-2nd/0735619670/"&gt;“Code Complete”&lt;/a&gt; describes this effect as “writing in programming language” opposed to “writing with help of the programming language”. In that book, you may find a very profound explanation of how to write a program for people, not for computers.&lt;/p&gt;

&lt;p&gt;Try to make the file tree self-explanatory, and try to extend generic terms, like &lt;code&gt;utils&lt;/code&gt;, &lt;code&gt;models&lt;/code&gt;, &lt;code&gt;validators&lt;/code&gt;, and so on. As for me, is better to see the &lt;code&gt;utils&lt;/code&gt; directory with a single file per each helper-object instead of the single &lt;code&gt;utils&lt;/code&gt; file with all helpers inside and with dozens of lines of code. I am also not a big fan of shortened entity names. I’d rather spend yet another microsecond reading a complex name and catching the concept, rather than reading a shortened but ambiguous one. All of those points sound obvious, but save hours of time in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Can you easily run the project or its test suite locally with a simple command?
&lt;/h2&gt;

&lt;p&gt;This will check how easy it is to pick up the project by a team members (especially newcomers).&lt;/p&gt;

&lt;p&gt;We usually do not want to spend an hour in order to find all possible startup options and distract our colleagues by asking corresponding questions. Some kind of command automation utility may help. &lt;/p&gt;

&lt;p&gt;I use good old &lt;a href="https://en.wikipedia.org/wiki/Make_(software)#Makefile"&gt;Makefile&lt;/a&gt; where I keep all needed complex commands associated with shortcuts like: &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;deploy&lt;/code&gt;, &lt;code&gt;bootstrap&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;clean&lt;/code&gt;, etc. I also add a “help section” to it, which prints a brief explanation of all commands and a couple of examples so that any team member can just type &lt;code&gt;make help&lt;/code&gt; in the command line and recall all details. It is much easier to run &lt;code&gt;make image test clean&lt;/code&gt; or something like that instead of typing long docker or docker-compose related commands and try to remember commands specific to each project. I am also happy when the CI/CD config may run those Makefile commands. That helps to keep all possible ways to run and manage application in a single place.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Can you add support for the "--dry-run" flag without a significant redesign of the project itself and its tests?
&lt;/h2&gt;

&lt;p&gt;This will check whether your business logic is tightly coupled with the database and external services.&lt;/p&gt;

&lt;p&gt;By this “dry run” mode I mean the ability to run the service with isolated or mocked external dependencies. We need this not only to perform manual testing and debugging but also to increase testability and extensibility of the project. This topic is described in details in the &lt;a href="https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/"&gt;“Architecture Patterns with Python”&lt;/a&gt; book by Harry Percival and Bob Gregory. As written in the book - "patching out the dependency you’re using makes it possible to unit test the code, but it does nothing to improve the design. For that, you’ll need to introduce abstractions". As for unit testing, there is two most popular approaches for testing external calls: London-school TDD using Mocks (patching the call in place) and the Classic Style using Fakes (Fakes are working implementations of the thing they’re replacing). Dynamic languages such as Python allow you to simplify the structure and just monkey-patch all needed calls. But, strictly speaking, mocking is a code smell and may lead to complicated tests.&lt;/p&gt;

&lt;p&gt;My choice is - Mocks for small or short-term solutions and Fakes for the medium/big and long-lasting ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Can you add support for the new version of the API/Model without a significant redesign of the project itself and its tests?
&lt;/h2&gt;

&lt;p&gt;This check is like the previous one but examines extensibility of the business logic-related parts of the application. &lt;/p&gt;

&lt;p&gt;Not the severe point, but it is better to think about the place for different versions of the same entities ahead of time and about how they may live together within the particular code base. &lt;/p&gt;

&lt;p&gt;In my personal experience, the initial version of the API or business logic entities seems the most proper one and stable, but the stable requirements are a myth. The task to add a new API version usually comes when the service is already deployed to the production and making such a change involves lots of steps with further refactoring. As proposed in the famous &lt;a href="https://twitter.com/kentbeck/status/250733358307500032"&gt;tweet&lt;/a&gt;: “Make the change easy (warning: this may be hard), then make the easy change.”&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Can you add support for the new interface, e.g. CLI without a significant redesign of the project itself and its tests?
&lt;/h2&gt;

&lt;p&gt;This will check whether your business logic is tightly coupled with the representation layer. &lt;/p&gt;

&lt;p&gt;If so, it would be much harder to add a new external interface or to build a healthy testing-pyramid. Loose coupling of the business logic with the representation layers (actual HTTP endpoints in case of a web application) helps us to simplify unit tests and to prepare to switching to another framework. That switch might look like an impossible case, but in my opinion, it is often almost impossible to painlessly switch to a better framework just because of the tightly coupled code. Not because we do not want to switch to the better framework. It is usually not just a major refactoring, it means rewriting the major portion of the code (and tests), which is not desirable at all. &lt;/p&gt;

&lt;p&gt;I’m going to suggest here any kind of approach based on the inversion of control. The &lt;a href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)"&gt;Hexagonal architecture&lt;/a&gt; or any of its &lt;a href="https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)#Variants"&gt;variants&lt;/a&gt; should work. Such kind of code structure makes it easy to separate business logic from representation and persistence layers or to add new layers as the Web interface besides existing CLI Interface and vice versa. Although using such approaches for small or short-term solutions may be an overkill.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Are there any unused/unnecessary dependencies in the source code?
&lt;/h2&gt;

&lt;p&gt;This will check whether the code base depends on things it doesn't use.&lt;/p&gt;

&lt;p&gt;Although we mostly use open-sourced dependencies, the risk of having related security issues is still there. Also, each added dependency does not decrease the compile time/startup time/binary size (depending on the particular programming language) of the service. For the same reasons, it is better not to keep testing-related dependencies in a production image/binary. There are also cases when we add dependency on the whole package if we actually need one or two helper functions from it. In most cases, it is better to copy-paste those helper functions into your code base and get rid of the extra dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Does the source code have a “gentleman set” of root-level helper files?
&lt;/h2&gt;

&lt;p&gt;This will check, I'd say, the general "maturity" of the repository.&lt;/p&gt;

&lt;p&gt;There is a set of commonly used files, which doesn't influence the functionality itself but helps us to maintain the codebase in a unified manner.&lt;br&gt;
Such files are: &lt;code&gt;.gitignore&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt;, &lt;code&gt;.editorconfig&lt;/code&gt;, &lt;code&gt;CHANGELOG.md&lt;/code&gt;, &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, explicit configs for static code analyzers? And by the way... the actual version of the &lt;code&gt;Readme&lt;/code&gt; file. No joke. Let’s end the practice when the main contributors to the readme file are newcomers, who found that steps described in the &lt;code&gt;Readme&lt;/code&gt; file do not work anymore...&lt;/p&gt;

&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note that I deliberately skipped any checks for unit-tests as they deserve a separate checklist.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the main goals of such a strict inspection is to increase the readability and maintainability of the project. This is extremely important for long-lasting projects. In most cases, we shouldn’t bother a lot about how easy it will be for a processor to parse our code base and create a nice abstract syntax tree from it. But we should bother about how much time it will take for a newcomer/your colleague/yourself to find the right place for a new feature or a bug fix. Let’s be honest, human beings are not so good at keeping a lot of objects and abstractions in memory simultaneously. We shouldn’t neglect our natural peculiarities and help ourselves in any ways possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliography:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.oreilly.com/library/view/code-complete-2nd/0735619670/"&gt;McConnell, Steve. 2004. Code Complete, 2nd Edition&lt;/a&gt; &lt;br&gt;
&lt;a href="https://www.oreilly.com/library/view/architecture-patterns-with/9781492052197/"&gt;Percival, Harry and Gregory, Bob. 2020. Architecture Patterns with Python&lt;/a&gt;&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>programming</category>
      <category>microservices</category>
    </item>
  </channel>
</rss>
