<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Zaur's Thoughts</title><link href="https://zaurnasibov.com/" rel="alternate"/><link href="https://zaurnasibov.com/feeds/all.atom.xml" rel="self"/><id>https://zaurnasibov.com/</id><updated>2025-11-08T18:15:00+02:00</updated><subtitle>Zaurun Fikirləri</subtitle><entry><title>The "Handover" teams</title><link href="https://zaurnasibov.com/posts/2025/11/08/handover-teams.html" rel="alternate"/><published>2025-11-08T18:15:00+02:00</published><updated>2025-11-08T18:15:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-11-08:/posts/2025/11/08/handover-teams.html</id><summary type="html">&lt;p class="first"&gt;Are you about to adopt a product via a &amp;quot;handover session&amp;quot;?
Perhaps you want to delay that moment and reconsider your options.&lt;/p&gt;
&lt;div class="last figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/posts/2025/11/08/handover-teams.html"&gt;
&lt;img alt="A short handover session between teams" src="https://zaurnasibov.com/articles/2025-10-05-handover-team/img/handover-session.webp" style="width: 100%;" /&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;Good luck to the Blue team!&lt;/p&gt;
&lt;/div&gt;
</summary><content type="html">&lt;p&gt;Do you know what my favourite corporate sin is when it comes to code bases?
It's a &lt;strong&gt;handover&lt;/strong&gt; from one team to another.
&amp;quot;But wait, Zaur, there are legitimate reasons for handovers!&amp;quot;
Of course there are.
Organisations are evolving structures, and sooner or later quite a few parts
attached to one of the limbs will be cut off and stitched to the other.
The code bases follow.&lt;/p&gt;
&lt;p&gt;We can't avoid handovers, and it's our job - as the source team,
and more importantly, as the receiving team to make a code handover
as smooth as possible.
But the process is so often compressed into a half-day &amp;quot;handover session&amp;quot;,
after which the source team wishes all the luck in the world to the new
owners and blasts off to their new adventures.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2025-10-05-handover-team/img/handover-session.svg"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-10-05-handover-team/img/handover-session.svg" style="width: 100%;" type="image/svg+xml"&gt;A short handover session between teams&lt;/object&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;Good luck to the Blue team!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Do you truly own the code at this point?
You can own the code on paper, but you truly own the code only when you know
it inside out, can picture data flows with your eyes closed, understand
the architecture, and have lived the decisions made along the way.
Your code is part of you - your experience, your knowledge, your skills,
your vision.
Simply put, you have to get intimate with the code to own it.&lt;/p&gt;
&lt;p&gt;You see where I'm going with this - no amount of &amp;quot;handover&amp;quot; will make you
the true owner of the code, at least not immediately.
You'll get there eventually, with time and
the hundreds and thousands of lines added and removed by you.
To smoothen the transition period, you'll need help from the source team.&lt;/p&gt;
&lt;div class="section" id="working-together"&gt;
&lt;h2&gt;Working together&lt;/h2&gt;
&lt;p&gt;What if, instead of having a handover session, you had a handover period
in which both teams form a single virtual team and work together?
And by working together I mean &lt;strong&gt;mob/ensemble programming&lt;/strong&gt; sessions, in which
knowledge gets shared and slowly transferred from one team to another.
You write new code, fix bugs, do maintenance and refactoring, release and monitor
- all with the specialists from the source team.
If the teams are not physically co-located, try to get together
and work together for a few days - this will create a strong bond between you.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2025-10-05-handover-team/img/handover-period.svg"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-10-05-handover-team/img/handover-period.svg" style="width: 100%;" type="image/svg+xml"&gt;A short handover session between teams&lt;/object&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;Blue team truly owns the product
after working together with the orange team.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="i-was-there-gandalf"&gt;
&lt;h2&gt;I was there, Gandalf&lt;/h2&gt;
&lt;p&gt;I've been through different handovers, some lasted hours, others months.
The first left me with a feeling of emptiness, dissatisfaction and anger:
&amp;quot;How anyone in their right mind expect me to maintain and work on this code?&amp;quot;.
The latter were quite the opposite - after weeks of hands-on experience with
the product and its code base,
our team had a solid &amp;quot;know-how&amp;quot; foundation under our feet,
and we were eager to take over and drive it further.&lt;/p&gt;
&lt;p&gt;Why did I accept the first one? Because I was young and green.
I accepted business needs as challenges, and threw myself into the fire with
no hesitation (Am I not a professional?).
I never considered the long-term consequences.
Then they hit. Business demanded new features,
but I couldn't deliver because I didn't truly own the code.&lt;/p&gt;
&lt;p&gt;Lessons learned.Today I thoroughly explain to the business all the risks
associated with rushed handovers. Instead, we design a migration plan -
together with the business, the old team, and the new teams.
Then we work together: fix bugs, deliver new features, make experiments and
monitor them in production.
When migration period is over, we are the true new owners of the code base.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="software development"/><category term="teams"/><category term="good practices"/><category term="programming"/><category term="handover"/><category term="mob programming"/></entry><entry><title>Fixing low display brightness on LUKS password prompt</title><link href="https://zaurnasibov.com/posts/2025/08/19/laptop-boot-time-display-brightness.html" rel="alternate"/><published>2025-08-19T22:34:00+03:00</published><updated>2025-08-19T22:34:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-08-19:/posts/2025/08/19/laptop-boot-time-display-brightness.html</id><summary type="html">&lt;p class="first"&gt;The problem:
The laptop display brightness fluctuates after booting when running on &lt;em&gt;battery&lt;/em&gt; power.&lt;/p&gt;
&lt;a class="reference external image-reference last" href="https://zaurnasibov.com/posts/2025/08/19/laptop-boot-time-display-brightness.html"&gt;
&lt;img alt="Explain what's in the image" class="align-center" src="https://zaurnasibov.com/articles/2025-08-19-laptop-display-brightness-boot/img/luks-password-prompt.webp" /&gt;
&lt;/a&gt;
</summary><content type="html">&lt;img alt="LUKS password prompt" class="align-center" src="https://zaurnasibov.com/articles/2025-08-19-laptop-display-brightness-boot/img/luks-password-prompt.webp" /&gt;
&lt;p&gt;&lt;strong&gt;Given:&lt;/strong&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Framework Laptop 13 AMD 7040 edition;&lt;/li&gt;
&lt;li&gt;Arch Linux with busybox-based initrd;&lt;/li&gt;
&lt;li&gt;Encrypted drive: LVM partitions on LUKS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; The laptop display brightness fluctuates after booting when running on &lt;em&gt;battery&lt;/em&gt; power.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;At first, the brightness is rather high, and systemd-boot entries
are clearly visible.&lt;/li&gt;
&lt;li&gt;However, after selecting the kernel to boot, the brightness drops to minimum.
You hardly see anything when the boot reaches LUKS password prompt.&lt;/li&gt;
&lt;li&gt;The boot process continues after successfully entering the password.
When systemd kicks in, the systemd-backlight service restores
the brightness.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; set a brightness on startup via a udev rule.&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Add a new udev rule which sets brightness through ACPI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;SUBSYSTEM==&amp;quot;backlight&amp;quot;, ACTION==&amp;quot;add&amp;quot;, KERNEL==&amp;quot;amdgpu_bl1&amp;quot;, ATTR{brightness}=&amp;quot;20000&amp;quot;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;save it to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/udev/rules.d/10-backlight.rules&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Include the rule path to mkinitcpio's configuration in &lt;tt class="docutils literal"&gt;/etc/mkinitcpio.conf&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;FILES = (&amp;quot;/etc/udev/rules.d/10-backlight.rules&amp;quot;)
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Generate a new initrd by running &lt;tt class="docutils literal"&gt;mkinitcpio &lt;span class="pre"&gt;-P&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Take out the power cable and reboot the machine.
Enjoy the visible decryption password prompt :).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content><category term="Articles"/><category term="archlinux"/><category term="linux"/><category term="framework-laptop"/><category term="laptop"/><category term="brightness"/><category term="display"/></entry><entry><title>The Power of Atomic Habits</title><link href="https://zaurnasibov.com/posts/2025/08/18/atomic-habits.html" rel="alternate"/><published>2025-08-18T22:02:00+03:00</published><updated>2025-08-18T22:02:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-08-18:/posts/2025/08/18/atomic-habits.html</id><summary type="html">&lt;p class="first"&gt;So, you want to get rid of a bad habit or acquire a good one?
The good news is that you have already taken the first step — you are aware
of your current situation and you've set a goal.
Where people usually fail is in the implementation.
How can you convert the desire to change into something that
becomes part of your identity?
Let the &amp;quot;Atomic Habits&amp;quot; by James Clear to guide you in this
thrilling quest.&lt;/p&gt;
&lt;a class="reference external image-reference last" href="https://zaurnasibov.com/posts/2025/08/18/atomic-habits.html"&gt;
&lt;img alt="Atomic Habits book cover" class="align-center" src="https://zaurnasibov.com/articles/2025-08-16-atomic-habits/img/cover.webp" /&gt;
&lt;/a&gt;
</summary><content type="html">&lt;!-- started writing on 2025.08.14 --&gt;
&lt;img alt="Atomic Habits book cover" class="align-center" src="https://zaurnasibov.com/articles/2025-08-16-atomic-habits/img/cover.webp" /&gt;
&lt;p&gt;We shape our habits and our habits shape us.
You go to sleep late every day — that's a habit.
Do you wake up early?
That's also a habit.
You always eat dessert after dinner?
You play violin at 5 o'clock in the evening?
You kiss your kids good-night every day?
You get a bottle of wine every time you go grocery shopping?
So many things we do without thinking much about them!
Things that have become our second nature, our identity.
Behaviours we would like to stick with or get rid of.
At the end of the day, most of them are &lt;strong&gt;habits&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;On the surface, a habit is a really simple thing.
It's a behavioural pattern we repeat again and again in similar situations.
When you want a routine to stick, you need to repeat it often, until it becomes
your second nature.
And if it's a bad habit you want to break, you just need to stop doing it
and avoid repeating it in the future.
Ah, if only it were that easy!&lt;/p&gt;
&lt;p&gt;The good news is that you have already taken the first step — you are aware
of your current situation and you've set a goal.
Where people usually fail is in the implementation.
How can you convert the desire to change into something that
becomes part of you?
Let &amp;quot;Atomic Habits&amp;quot; by James Clear to guide you in this
thrilling quest.&lt;/p&gt;
&lt;p&gt;There is a reason the book topped the New York Times best-seller list
for 164 weeks.
It explains how our evolutionary ancestry affects human
behaviour and habits
and provides practical tools developed by the author
to help readers cultivate the habits and becoming the type of
person they want to be.&lt;/p&gt;
&lt;p&gt;James describes a habit as a loop consisting of four stages:
&lt;em&gt;cue&lt;/em&gt;, &lt;em&gt;craving&lt;/em&gt;, &lt;em&gt;response&lt;/em&gt;, and &lt;em&gt;reward&lt;/em&gt;.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2025-08-16-atomic-habits/img/the-habit-loop.webp"&gt;
&lt;img alt="The Habit Loop" src="https://zaurnasibov.com/articles/2025-08-16-atomic-habits/img/the-habit-loop.webp" style="width: 50%;" /&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;A &lt;strong&gt;cue&lt;/strong&gt; is a trigger that initiates the behaviour, which is expected to
result in a reward.
Just yesterday, I came home from work and found my daughter eating
an ice-cream.
I was hungry, and that cue signalled that I could quickly deal with
the hunger by grabbing an ice-cream!&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;craving&lt;/strong&gt; is a desire that follows a cue.
I want an ice-cream!
I start imagining how it melts on my tongue, its sweetness and texture.
The urge for sugar rush kicks in, drowning out the
reasonable voice in my head saying
that perhaps I should first have a proper supper.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;response&lt;/strong&gt; is the action.
I rush to the kitchen, and grab an ice-cream from the freezer.
I unwrap it impatiently and sink my teeth into the frozen flesh.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;reward&lt;/strong&gt; is the outcome that satisfies a craving
and &lt;em&gt;reinforces a behaviour&lt;/em&gt;.
The latter part is crucial, because reinforcement is what makes the behaviour
more likely to be repeated in future.
In my case, the reward was the pleasant taste of the ice-cream and
no longer feeling hungry.
Though the &amp;quot;Why did I just do it, instead of dining properly?&amp;quot;
question pops up right after :).
Indeed, you're truly free only when you are in control of your cravings!&lt;/p&gt;
&lt;p&gt;Building a new habit requires creating this loop, while breaking a habit
means breaking the loop.
This &amp;quot;technical&amp;quot; task is a mere facade.
To make it work, you've got to make the habit part of who you are, part of your
identity, and it is not easy at all.
That's why James recommends starting with &amp;quot;atomic&amp;quot; habits - small,
but regular steps which nudge you toward your new self.&lt;/p&gt;
&lt;p&gt;Note how he avoids the &amp;quot;goals&amp;quot; and the &amp;quot;results&amp;quot;.
Losing 5 kilos is a goal and an impressive result,
but becoming &lt;em&gt;a person who has healthy eating habits and regularly exercises&lt;/em&gt; is the mission.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;The problem with a goals-first mentality is that you're continuously
putting happiness off until the next milestone.&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;The true question is: &amp;quot;Are you becoming the type of person you want
to become?&amp;quot; The first step is not what or how, but who.
You need to know who you want to be.
Otherwise, your quest for change is like a boat without a rudder.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;One small step at a time — eating sweets only once a day, then once every second
day, then once every third day - as long as you stick to the rules,
you've cracked it!
Although, we've all been there trying hard and inevitably failing.
That's when James introduces the framework called
the &lt;em&gt;Four Laws of Behavior Change&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In a nutshell, to build a new habit you need to:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The 1st law (Cue): &lt;em&gt;Make it obvious.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The 2nd law (Craving): &lt;em&gt;Make it attractive.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The 3rd law (Response): &lt;em&gt;Make it easy.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The 4th law (Reward): &lt;em&gt;Make it satisfying.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contrary, to break a bad habit you need to invert the laws:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Inversion of the 1st law (Cue): &lt;em&gt;Make it invisible.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Inversion of the 2nd law (Craving): &lt;em&gt;Make it unattractive.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Inversion of the 3rd law (Response): &lt;em&gt;Make it difficult.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Inversion of the 4th law (Reward): &lt;em&gt;Make it unsatisfying.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;James dives deep into these laws, shares examples,
gives you tools — all so you don't have to rely on the scarce
&lt;em&gt;willpower&lt;/em&gt;, but rather build a &lt;em&gt;system&lt;/em&gt; that actually helps you
build and break habits.
As you flip the last page of the book, you realise, that the only thing
standing between you and that amazing future yourself - is just you.&lt;/p&gt;
&lt;p&gt;One thing I'd add from my own mess-ups: breaking
a habit isn't just about stopping — it's also about swapping.
The cue and craving might be unavoidable, but you can
tweak the response.
(Disclosure: this is my experience, but not my original thoughts, they
come from another book I love and recommend -
&lt;a class="reference external" href="https://charlesduhigg.com/the-power-of-habit/"&gt;&amp;quot;The Power of Habit&amp;quot;&lt;/a&gt;
by Charles Duhigg.)&lt;/p&gt;
&lt;p&gt;Habits, as James Clear says, are simply reliable solutions to recurring
problems in our environment.
But people who don't have their habits sorted? They're often the least free.
Do you feel like your freedom was taken away?
You can take it back — one atomic habit at a time!&lt;/p&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="habits"/></entry><entry><title>xkbcommon and my custom Russian phonetic layout</title><link href="https://zaurnasibov.com/posts/2025/08/01/xkbcommon-and-my-custom-russian-phonetic-layout.html" rel="alternate"/><published>2025-08-01T12:00:00+03:00</published><updated>2025-08-01T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-08-01:/posts/2025/08/01/xkbcommon-and-my-custom-russian-phonetic-layout.html</id><summary type="html">&lt;p class="first"&gt;The Soviet Union officially dissolved in 1991, but Russian language remained
the region's lingua franca for decades.
Many children of my generation were simultaneous bilinguals;
we spoke both Azeri and Russian since childhood.
I learned to type in Russian,
but I never ever learned the official Windows Russian
keyboard layout, because I didn't have a keyboard with Russian alphabet
printed on it.
The alternative was a phonetic layout, and I still remember
a program called &amp;quot;Alt-Win&amp;quot;, which allowed to select Azeri Latin,
or Russian phonetic keyboard layouts in Windows 9x.
Over the years, I used other tools in Windows XP and Windows 7 to recreate
this layout. And then I moved to Linux.&lt;/p&gt;
&lt;p&gt;In Linux, the only tool you need to create your own keyboard layout
is a text editor.
Would you like to find out how?&lt;/p&gt;
&lt;a class="reference external image-reference last" href="https://zaurnasibov.com/posts/2025/08/01/xkbcommon-and-my-custom-russian-phonetic-layout.html"&gt;
&lt;img alt="Explain what's in the image" class="align-center" src="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/img/keymap.webp" /&gt;
&lt;/a&gt;
</summary><content type="html">&lt;p&gt;The Soviet Union officially dissolved in 1991, but Russian language remained
the region's lingua franca for decades.
Many children of my generation were simultaneous bilinguals;
we spoke both Azeri and Russian since childhood.
I learned to type in Russian,
but I never ever learned the official Windows Russian
keyboard layout, because I didn't have a keyboard with Russian alphabet
printed on it.
The alternative was a phonetic layout, and I still remember
a program called &amp;quot;Alt-Win&amp;quot;, which allowed to select Azeri Latin,
or Russian phonetic keyboard layouts in Windows 9x.
Over the years, I used other tools in Windows XP and Windows 7 to recreate
this layout. And then I moved to Linux.&lt;/p&gt;
&lt;p&gt;In Linux, the only tool you need to create your own keyboard layout
is a text editor.
Since you are already reading this, scroll down to feed your curiosity!&lt;/p&gt;
&lt;img alt="Explain what's in the image" class="align-center" src="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/img/keymap.webp" /&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;In this article, I refer to Russian phonetic keyboard layouts as keyboard
layouts where Russian letters are mostly located at their similarly sounding
letters in English, on US QWERTY keyboard.
For example, the Russian letters &amp;quot;а&amp;quot;, &amp;quot;о&amp;quot;, &amp;quot;м&amp;quot;, &amp;quot;т&amp;quot; are typed using
the English &amp;quot;a&amp;quot;, &amp;quot;o&amp;quot;, &amp;quot;m&amp;quot;, &amp;quot;t&amp;quot; keys.&lt;/p&gt;
&lt;p class="last"&gt;The trick is to map 33 Russian alphabet letters
to a keyboard that has only 26 Latin letters (used in English)
while retaining the necessary punctuation marks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="custom-layout-the-naive-way"&gt;
&lt;h2&gt;Custom layout - the naive way&lt;/h2&gt;
&lt;p&gt;The naive way to create a custom layout is by modifying an existing
variant definition in one of the symbols files from &lt;tt class="docutils literal"&gt;/usr/share/X11/xkb/symbols&lt;/tt&gt;.
That's what I originally did — I modified the &lt;tt class="docutils literal"&gt;ru&lt;/tt&gt; file and its &lt;tt class="docutils literal"&gt;phonetic&lt;/tt&gt;
section:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;partial alphanumeric_keys
xkb_symbols &amp;quot;phonetic&amp;quot; {

    name[Group1]= &amp;quot;Russia - Phonetic&amp;quot;;

    key &amp;lt;TLDE&amp;gt;   {[       Cyrillic_yu,       Cyrillic_YU ]};
    key &amp;lt;AE01&amp;gt;   {[                 1,            exclam ]};
    key &amp;lt;AE02&amp;gt;   {[                 2,                at ]};
    key &amp;lt;AE03&amp;gt;   {[                 3,        numbersign ]};
    ...
    ...
}
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here, the first column contains the symbolic key names &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;,
the second column contains the corresponding key symbol for a key pressed
without modifiers,
and the last column contains the key symbol for a key pressed with Shift.&lt;/p&gt;
&lt;p&gt;This works, BUT your user needs write permissions for the file,
and the file will be overwritten anyway every time XKB gets updated by the system.&lt;/p&gt;
&lt;p&gt;Can you believe that for over 15 years I used the same customised &lt;tt class="docutils literal"&gt;ru&lt;/tt&gt; symbols
file, and replaced the upstream file over and over?
I did this manually every time the package responsible for &lt;tt class="docutils literal"&gt;/usr/share/X11/xkb&lt;/tt&gt;
got updated. The file followed me as I moved from Ubuntu to Debian,
and from Debian to Arch. And honestly speaking,
I never bothered to dig deeper and learn the mechanisms behind the command
to set up my desired layouts:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
setxkbmap -layout 'us,fi,ru,az' -variant ',,phonetic,' -option grp:shifts_toggle
&lt;/pre&gt;
&lt;p&gt;That allowed me to cycle through US, Finnish, Russian phonetic and Azeri layouts
by pressing both shifts.&lt;/p&gt;
&lt;p&gt;This changed when I installed Arch on
&lt;a class="reference external" href="https://zaurnasibov.com/posts/2025/07/20/framework-laptop-is-awesome.html"&gt;my new laptop&lt;/a&gt;.
I finally decided to find a &amp;quot;smart way&amp;quot; and learn the mechanisms behind
layouts in Linux graphical environments.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bits-about-xkb"&gt;
&lt;h2&gt;Bits about XKB&lt;/h2&gt;
&lt;p&gt;Imagine a system with a graphical environment backed by Wayland compositor.
Let's find out how pressing a key on the keyboard results in a symbol appearing
in an application. I'll omit deep technicalities to keep the narrative short.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/img/xkb-diagram.svg"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/img/xkb-diagram.svg" style="width: 100%;" type="image/svg+xml"&gt;Diagram explaining how pressing a keyboard key ends up in application
while passing through libxkbcommon.&lt;/object&gt;
&lt;/a&gt;
&lt;p class="caption"&gt;A high-level diagram of how a key press event travels from a keyboard to
a user-space application.&lt;/p&gt;
&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Wayland compositor notifies the application about the current keymap
configuration. This happens when application starts or the user changes
keyboard layout.
The application loads the keymap via &lt;strong&gt;xkbcommon&lt;/strong&gt; library.&lt;/li&gt;
&lt;li&gt;The keyboard device sends a hardware signal - a &lt;em&gt;scancode&lt;/em&gt;
to the Linux Kernel.&lt;/li&gt;
&lt;li&gt;The kernel's evdev subsystem
maps the scancode to a &lt;em&gt;keycode&lt;/em&gt; - a representation abstracted from hardware.&lt;/li&gt;
&lt;li&gt;Wayland compositor uses libinput to receive keyboard and other input
device events from the kernel. It notifies the application (a Wayland client)
about a pressed/released key with a &lt;em&gt;keycode&lt;/em&gt;, and &lt;em&gt;modifiers&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The application (using GTK, Qt, or other Wayland client implementations)
passes the &lt;em&gt;loaded keymap context&lt;/em&gt;, the &lt;em&gt;keycode&lt;/em&gt; and &lt;em&gt;modifiers&lt;/em&gt; to &lt;strong&gt;xkbcommon&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;xkbcommon applies keycodes/compat/geometry/symbols/types (KcCGST)
configuration &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;, to map the input to the final symbol.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In a nutshell, it's xkbcommon's job to translate
&lt;tt class="docutils literal"&gt;Shift + L&lt;/tt&gt; keystroke to Cyrillic &lt;tt class="docutils literal"&gt;Л&lt;/tt&gt; symbol, when I have my Russian
phonetic layout activated.&lt;/p&gt;
&lt;p&gt;As Daniel Stone, the maintainer of xkbcommon nicely puts it:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
It’s about two things: parsing and loading keymaps, and managing their
ongoing state. State, in terms of keyboards, is the usual suspects —
modifiers (e.g. Shift, Alt), multiple layouts (mostly for multiple languages),
and LEDs. In general, you only want one person keeping a canonical copy
of the state, and distributing it to its clients, as both the X server
and Wayland do today.
xkbcommon allows for this mode of operation, and is indeed how all
current Wayland clients handle keyboard input &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;.&lt;/blockquote&gt;
&lt;div class="section" id="historical-reference"&gt;
&lt;h3&gt;Historical reference&lt;/h3&gt;
&lt;p&gt;X Keyboard Extension (XKB) protocol
was developed in early 1990s and included in
X Window System, Version 11 Release 6 (X11R6) in May 1994 &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;.
XKB extends the core X protocol by offering support for&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Multiple keyboard layouts&lt;/li&gt;
&lt;li&gt;Sophisticated modifier handling&lt;/li&gt;
&lt;li&gt;LED control&lt;/li&gt;
&lt;li&gt;Keyboard geometry description,&lt;/li&gt;
&lt;li&gt;Various keyboard behaviors beyond what the core X protocol provides &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-5"&gt;[5]&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rather than reinventing the wheel, Wayland protocol currently relies on XKB
format for keymaps. Unlike X11, where clients received a symbolic representation
of the key, in Wayland it's up to the clients to interpret keyboard
events and map the pressed keys to symbols.
xkbcommon library is typically used for this purpose.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="custom-layout-the-smart-way"&gt;
&lt;h2&gt;Custom layout - the smart way&lt;/h2&gt;
&lt;p&gt;The xkbcommon documentation comes with a tutorial on adding a custom
keyboard layout &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-6"&gt;[6]&lt;/a&gt;.
I don't want to repeat that here, and rather encourage you to dive
into it and get the information from the original source.&lt;/p&gt;
&lt;p&gt;However, I'll briefly describe my Russian Alternative Phonetic setup.&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;div class="first line-block"&gt;
&lt;div class="line"&gt;&lt;strong&gt;Symbols file:&lt;/strong&gt;&lt;/div&gt;
&lt;div class="line"&gt;I placed my custom layout variant in a new symbols file
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$HOME/.config/xkb/symbols/ru_alternative&lt;/span&gt;&lt;/tt&gt;.
This file contains translation of symbolic key codes into the desired
key symbols (&lt;a class="reference external" href="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/data/ru_alternative.html"&gt;link&lt;/a&gt;).&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;div class="first line-block"&gt;
&lt;div class="line"&gt;&lt;strong&gt;Rules file:&lt;/strong&gt;&lt;/div&gt;
&lt;div class="line"&gt;I added a rule to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.config/xkb/rules/evdev&lt;/span&gt;&lt;/tt&gt; file
(&lt;a class="reference external" href="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/data/evdev.html"&gt;link&lt;/a&gt;).
The purpose of the rules file is to map between user-friendly configuration,
and the configuration used by &lt;em&gt;xkbcomp&lt;/em&gt; keymap compiler &lt;a class="footnote-reference" href="#footnote-7" id="footnote-reference-7"&gt;[7]&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;I made the layout discoverable in GNOME by adding an entry to
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/.config/xkb/rules/evdev.xml&lt;/span&gt;&lt;/tt&gt; (&lt;a class="reference external" href="https://zaurnasibov.com/articles/2025-08-01-xkbcommon-and-my-custom-phonetic-layout/data/evdev.xml.html"&gt;link&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That's it! A simple solution for a single-person machine,
and no more half-baked solutions with broken layouts after
system updates :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://xkbcommon.org/doc/current/keymap-text-format-v1.html#keycode-def"&gt;xkbcommon - The XKB keymap text format, V1 / Keycode&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://xkbcommon.org/doc/current/user-configuration.html#rmlvo-vs-kccgst"&gt;xkbcommon - RMLVO vs. KcCGST&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://www.fooishbar.org/blog/xkbcommon-intro/"&gt;xkbcommon: what is it?&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://www.x.org/wiki/X11R6/#index16h4"&gt;X Window System, Version 11 release 6 (X11R6)&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://deepwiki.com/mirror/libX11/5-x-keyboard-extension-(xkb)"&gt;DeepWiki - X Keyboard Extensions&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-6"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://xkbcommon.org/doc/current/user-configuration.html"&gt;xkbcommon - User Configuration&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-7" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-7"&gt;[7]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://xkbcommon.org/doc/current/rule-file-format.html"&gt;xkbcommon - Rule file format&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="linux"/><category term="xkb"/><category term="xkbcommon"/><category term="wayland"/><category term="layout"/><category term="russian"/><category term="phonetic"/></entry><entry><title>Framework Laptop is awesome!</title><link href="https://zaurnasibov.com/posts/2025/07/20/framework-laptop-is-awesome.html" rel="alternate"/><published>2025-07-20T23:16:00+03:00</published><updated>2025-07-20T23:16:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-07-20:/posts/2025/07/20/framework-laptop-is-awesome.html</id><summary type="html">&lt;p class="first"&gt;As I am writing this text, enjoying Finnish summer from an armchair in my backyard,
a feeling of satisfaction fills me. After nine years with a home desktop machine,
I'm finally back to using a personal laptop. I can once again work on my projects
from anywhere - from a sofa in the living room or an airplane 10 km above the ground.
&amp;quot;Good for you, Zaur, you've got a laptop, why are you so excited?&amp;quot;
Let's go back a few years ago. It all began with a loud rant...&lt;/p&gt;
&lt;a class="reference external image-reference last" href="https://zaurnasibov.com/posts/2025/07/20/framework-laptop-is-awesome.html"&gt;
&lt;img alt="Framework Laptop" class="align-center" src="https://zaurnasibov.com/articles/2025-07-17-framework-laptop-is-awesome/img/framework-cartoon.webp" /&gt;
&lt;/a&gt;
</summary><content type="html">&lt;!-- started writing on 2025-07-17 --&gt;
&lt;p&gt;As I am writing this text, enjoying Finnish summer from an armchair in my backyard,
a feeling of satisfaction fills me. After nine years with a home desktop machine,
I'm finally back to using a personal laptop. I can once again work on my projects
from anywhere - from a sofa in the living room or an airplane 10 km above the ground.
&amp;quot;Good for you, Zaur, you've got a laptop, why are you so excited?&amp;quot;
Let's go back a few years ago. It all began with a loud rant...&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/posts/2025/07/20/framework-laptop-is-awesome.html"&gt;
&lt;img alt="Framework Laptop" class="align-center" src="https://zaurnasibov.com/articles/2025-07-17-framework-laptop-is-awesome/img/framework-cartoon.webp" /&gt;
&lt;/a&gt;
&lt;div class="section" id="a-rant-about-a-broken-screen"&gt;
&lt;h2&gt;A rant about a broken screen&lt;/h2&gt;
&lt;p&gt;&amp;quot;...Dammit! I &lt;strong&gt;did&lt;/strong&gt; cut that antenna cable! Well, there's still one left.
Damn Lenovo and all modern electronics manufacturers!&amp;quot; - I cursed
every second of the two hours it took me to disassemble and reassemble
my better half's IdeaPad to swap
the broken screen. She had accidentally closed her laptop lid with a smart card
reader cable lying on the keyboard — resulting in the lower-right quarter
of the screen dying.&lt;/p&gt;
&lt;p&gt;&amp;quot;&lt;em&gt;Replacing a laptop screen — how hard can it be?&lt;/em&gt;&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It can be quite hard&lt;/strong&gt;. That's because nowadays we design electronics for
fast production, not &lt;em&gt;easy repairs&lt;/em&gt;. Even when the broken component is not
soldered into the motherboard, you need a ton of luck to find a replacement
part and fix things. You won't find any official manuals — perhaps only videos
made by kind people on Youtube.&lt;/p&gt;
&lt;p&gt;In my case, I had to
disassemble the chassis from both the top and bottom,
use a hairdryer to loosen the glued screen frame,
unfasten dozens of screws,
deal with fragile antenna cables (and yes, I ended up smashing and cutting one!).
All this — by following a video guide bought from a random Australian
laptops repair shop!&lt;/p&gt;
&lt;p&gt;That's when I promised myself: next time I buy a laptop, it's gonna be the
most repairable laptop out there. Little did I know, the Framework Laptop
had already been on the market for two years!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="imagine-a-laptop"&gt;
&lt;h2&gt;Imagine a laptop&lt;/h2&gt;
&lt;p&gt;Imagine a modern, &lt;strong&gt;sustainable&lt;/strong&gt; laptop. It should be designed to last,
be easily customisable and repairable.
That's the Framework Laptop in a nutshell.
It all starts at the web shop. Would you like a pre-built laptop with Windows,
or a DIY edition with components in separate boxes and no OS installed?
- Your choice!
Are your daily needs specific to two USB-A ports and an Ethernet port?
Sure thing!
Don't like the official memory and storage? Bring your own!
Want a display with a higher refresh rate? You've got it!
And that's just the tip of the iceberg.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="Framework Laptop configuration" src="https://zaurnasibov.com/articles/2025-07-17-framework-laptop-is-awesome/img/framework-configuration.webp" /&gt;
&lt;p class="caption"&gt;Configuring &lt;strong&gt;your&lt;/strong&gt; Framework Laptop.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The experience continues as you own it.
Is your display broken? The &lt;a class="reference external" href="https://guides.frame.work/Guide/Display+Replacement+Guide/86"&gt;official manual&lt;/a&gt;
will guide you to replace it in just ten minutes.
The only tool you'll need is a Torx/Philips screwdriver, which comes with the laptop.
Your battery doesn't hold a charge anymore? You know what to do.
Has it been a while, and you need the latest and fastest -generation processor?
Get a new motherboard, and put the old one into a case designed to convert
Framework mainboards into desktops!&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="Framework Laptop configuration" src="https://zaurnasibov.com/articles/2025-07-17-framework-laptop-is-awesome/img/case.webp" style="width: 80%;" /&gt;
&lt;p class="caption"&gt;Replaced an old but fully-functioning motherboard?
Why not give it a second life as a mini PC?&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Finally, imagine a laptop with full Linux support out of the box and
a great community of enthusiasts around it!
You clearly see, why Framework laptop is so appealing to me.&lt;/p&gt;
&lt;p&gt;What I also appreciate about Framework Computers Inc. is that their
&lt;a class="reference external" href="https://frame.work/sustainability"&gt;sustainability&lt;/a&gt; page starts with
a big, fat, and honest &lt;strong&gt;&amp;quot;We are not sustainable&amp;quot;&lt;/strong&gt; heading.
However, the page explains how the company aims to reduce
environmental impact by creating products that last longer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-chassis"&gt;
&lt;h2&gt;The chassis&lt;/h2&gt;
&lt;p&gt;The chassis quality is top-notch.
The light aluminium body and matte glass touchpad
look and feel beautiful! The bezel is made of plastic, but it's customisable
- you can choose from a handful of colours and transparent options.
The keyboard provides good feedback, and is quite comfortable
for long typing sessions. Its backlight is soft and adjustable.
Thin exhaust air vents at the back are a plus when you're using an external
mouse - you won't get your palm fried.&lt;/p&gt;
&lt;p&gt;The laptop is warm and rather silent for an x64 machine.
I can comfortably keep it on my lap under light coding/browsing workload
for hours, though it feels like burning compared to an M-series MacBook.
Watching 4K videos boosts the fan and the bottom plate gets noticeably hotter.&lt;/p&gt;
&lt;p&gt;The 13.5'' display has 3:2 aspect ratio — that's more vertical space
compared to the widespread 16:9. Perhaps not ideal for watching movies,
but amazing for vertical content: coding, writing documents, reading, and
web surfing. And guess what? The display even comes in two options:
the original 2.2K and the newer 2.8K with higher resolution
and refresh rate.&lt;/p&gt;
&lt;p&gt;The battery life is good for me, but there have been plenty of complaints
from the users.
I've restricted battery charging to 80% — this prolongs battery life,
and is more than enough to last for 4-5 hours of light workload, till
the charge drops to 30%. Which can be roughly approximated to 8-10 hours
of full-to-zero battery life — a solid result for an x64 laptop.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;img alt="Framework camera and microphone" src="https://zaurnasibov.com/articles/2025-07-17-framework-laptop-is-awesome/img/camera-mic.webp" /&gt;
&lt;p class="caption"&gt;Nothing beats hardware switches when it comes to privacy!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Oh, did I mention that there is a fingerprint reader and there are hardware
switches for the microphone and the camera?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="using-gnu-linux"&gt;
&lt;h2&gt;Using GNU/Linux&lt;/h2&gt;
&lt;p&gt;Getting into nerdy stuff — I ditched Windows from my computer back in 2007
and never looked back. So Linux support is paramount for me. It was also the
reason I got the &amp;quot;latest-minus-one&amp;quot; generation laptop — because all the issues
that may surface with the latest and greatest hardware have already been solved
for the previous generation.&lt;/p&gt;
&lt;p&gt;I am happy to say, that everything just works. It's been two weeks, and I
had zero problems. Oh, don't get me wrong, I'm still tuning and tinkering
with the setup (after all it's Arch Linux!).
There are issues, like the uncalibrated display, or imbalanced speakers
I've learned about from the fantastic
&lt;a class="reference external" href="https://wiki.archlinux.org/title/Framework_Laptop_13"&gt;Framework Laptop 13 wiki page&lt;/a&gt;.
Luckily, the community has created necessary colour profiles
to improve colour reproduction and equaliser presets to enhance the sound.
There are some other minor annoyances, like display automatic backlight
adjustment jumping in discrete steps, instead of changing gradually,
but all that can be fixed with proper software updates.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="shall-you-join-the-club"&gt;
&lt;h2&gt;Shall you join the club?&lt;/h2&gt;
&lt;p&gt;Before I say anything, I must make a confession: I like MacBook chassis,
especially the battery-life-to-processing-power ratio.
But I absolutely hate Apple's policies when it comes to
&lt;a class="reference external" href="https://www.youtube.com/watch?v=r0Hwb5xvBn8&amp;amp;t=958s"&gt;the right to repair&lt;/a&gt;.
As another example, compare
&lt;a class="reference external" href="https://www.ifixit.com/Guide/MacBook+Pro+14-Inch+Late+2023+(M3)+Fan+Replacement/167783"&gt;this&lt;/a&gt;
to
&lt;a class="reference external" href="https://guides.frame.work/Guide/Heatsink+and+Fan+Replacement+Guide/84"&gt;this&lt;/a&gt;.
So, let's assume you're also not an Apple person and you want a PC.
Should you get Framework Laptop?&lt;/p&gt;
&lt;p&gt;A pre-built Framework Laptop is more expensive than other manufacturers'
laptops with similar specs. However, money-wise it's about long-term savings
and voting with your wallet for a sustainable option.
But if you are making this choice, why not go with the more affordable
DIY edition from the start to get the full experience?
You can still get all components and even Windows from Framework.
It'll take you five minutes to assemble the chassis,
and about an hour to install Windows.&lt;/p&gt;
&lt;p&gt;And if you're Linux enthusiast or an IT professional — JUST GET IT :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="my-setup-specs-and-other-numbers-for-nerds"&gt;
&lt;h2&gt;My setup specs and other numbers for nerds&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Framework 13 DIY edition with 2.8k 2880x1920 screen, with &lt;a class="reference external" href="https://www.amd.com/en/products/processors/laptop/ryzen/7000-series/amd-ryzen-5-7640u.html"&gt;AMD Ryzen 5 7640u&lt;/a&gt;
CPU.&lt;/li&gt;
&lt;li&gt;Translucent Black bezel.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.crucial.com/memory/ddr5/CT2K16G56C46S5"&gt;Crucial 32GB RAM Kit (16GBx2) DDR5-5600&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.crucial.com/ssd/p3/ct2000p3ssd8"&gt;Crucial P3 2TB PCIe M.2 2280 SSD&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Ports: USB-C, USB-A, HDMI, SD Card.&lt;/li&gt;
&lt;li&gt;The CPU core temperature sensor (k10temp) showed the highest temperature
among other sensors. The values were 40°C for &amp;quot;light workload&amp;quot;,
50°C while playing YouTube FullHD videos,
and 60°C while playing FullHD 60FPS HVEC-encoded video.
The ACPI Thermal Zone sensors showed 35°C, 40°C and 50°C respectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="framework-laptop"/><category term="laptop"/><category term="linux"/></entry><entry><title>Hexagonal architecture and Python - Part IV: Lightweight integration tests</title><link href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html" rel="alternate"/><published>2025-05-10T18:00:00+03:00</published><updated>2025-05-10T18:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2025-05-10:/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html"&gt;
&lt;img alt="Pythons and hexagons with Part IV" class="align-center" src="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/hexarch-lightweight-integration-tests.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;It's pretty straightforward to unit test the components
of an application that follows Hexagonal Architecture.
The components are part of specific layers, and mocking
the next dependency layer is usually simple.
However, this approach means we never test the application
as a whole and have to rely on expensive integration or
end-to-end tests to do so.&lt;/p&gt;
&lt;p&gt;We can test the application components in &lt;em&gt;sociable&lt;/em&gt; manner,
leaving our components' direct dependencies as-is,
and pushing the mocks further to the application edges.&lt;/p&gt;
&lt;p class="last"&gt;If we push the mocks too far, we end up with
&lt;em&gt;lightweight integration tests&lt;/em&gt;.
Let's explore how we can utilise such tests in a context
of Django application and what benefits we can reap.&lt;/p&gt;
</summary><content type="html">&lt;!-- started writing on 2025-02-08 --&gt;
&lt;img alt="Pythons and hexagons with Part IV" class="align-center" src="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/hexarch-lightweight-integration-tests.webp" /&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;Part I: Dependency Injection and componential architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II: Domain,  Application Services, Ports and Adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html"&gt;Part III: Persistence, Transactions, Exceptions and The Final Assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html"&gt;Part IV: Lightweight integration tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/tree/blog4"&gt;The code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="intro"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-1"&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is very easy to unit test the components of an application
that follows Hexagonal architecture principles. The components
belong to certain layers, and it's quite straightforward to
mock the following dependency layer.
However, the problem with such an approach is that we never
test the application as a whole, and have to rely on expensive
integration or end-to-end tests to do so.&lt;/p&gt;
&lt;p&gt;We can test the application components in &lt;em&gt;sociable&lt;/em&gt; manner,
leaving our components' direct dependencies as-is,
and pushing the mocks further to the application edges.&lt;/p&gt;
&lt;p&gt;If we push the mocks too far, we end up with
&lt;em&gt;lightweight integration tests&lt;/em&gt;.
Let's explore how we can utilise such tests in a context
of Django application and what benefits we can reap.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;The original article focused on such &amp;quot;lightweight integration&amp;quot; tests.
I even dared to call them &amp;quot;sociable&amp;quot;!
&lt;a class="reference external" href="https://github.com/jmp"&gt;Jarkko &amp;quot;jmp&amp;quot; Piiroinen&lt;/a&gt; was very generous to
thoroughly review the article. He pointed that &lt;em&gt;sociable tests&lt;/em&gt;,
rather implies testing a thing within the application core (or &amp;quot;Application&amp;quot; in
&lt;a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture"&gt;Alistair Cockburn's definition&lt;/a&gt;)
with its neighbours/collaborators. Testing the whole flow by mocking the
rightmost calls is &amp;quot;sociable tests pushed too far&amp;quot;, or as Jarkko put it
&amp;quot;rather lightweight end-to-end tests&amp;quot;.&lt;/p&gt;
&lt;p&gt;The updated article is about exploring the ways to conduct such tests
in a Django application setup, focusing on the benefits and caveats.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr class="docutils" /&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;span id="hexarch-sociable-tests-part-4"&gt;&lt;/span&gt;&lt;p class="topic-title"&gt;&lt;a class="reference internal" href="#top"&gt;Table of Contents&lt;/a&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#intro" id="toc-entry-1"&gt;Intro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#hexagonal-architecture-as-described-in-the-articles-series" id="toc-entry-2"&gt;Hexagonal architecture - as described in the articles series&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#testing-the-application" id="toc-entry-3"&gt;Testing the application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#architecture-revised" id="toc-entry-4"&gt;Architecture revised&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#lightweight-integration-tests-driven-development" id="toc-entry-5"&gt;Lightweight integration tests -driven development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#use-case-vote-for-an-article" id="toc-entry-6"&gt;Use case: Vote for an article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#use-case-only-existing-user-can-vote-for-an-article" id="toc-entry-7"&gt;Use case: Only existing user can vote for an article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-price-to-pay" id="toc-entry-8"&gt;The price to pay&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#conclusion" id="toc-entry-9"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#acknowledgements" id="toc-entry-10"&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Time flies (darn, I say that again)!
I wrote the original &amp;quot;Hexagonal Architecture and Python&amp;quot; series
back in 2022, which was only three years ago
(&lt;em&gt;honestly, it feels like yesterday!&lt;/em&gt;)
Since then my understanding of RESTful API design and Domain-Driven Design
has deepened. But the biggest shift, however, has occurred in where I start
and how I test.&lt;/p&gt;
&lt;p&gt;I used to believed that the &lt;em&gt;implementation&lt;/em&gt; of the domain model should precede
exposing any API. I still &lt;em&gt;design&lt;/em&gt; the domain model first before deriving API structure
from if. However, I &lt;em&gt;implement&lt;/em&gt; barebones API first, initially hard-coding and
short-circuiting domain logic, to enable early integrations and
feedback.
This approach helps steer the development in the right direction,
keeps API consumers happy and avoids &amp;quot;big bang&amp;quot; release surprises.&lt;/p&gt;
&lt;p&gt;This led to the second change. I used to TDD every layer and every component
of the application &lt;em&gt;independently&lt;/em&gt;. Today, I aim at unit testing the
interconnected parts of the system.&lt;/p&gt;
&lt;p&gt;Bear in mind, that the system users often don't care about what's happening
under its hood.
They are more concerned with the system's public contract - its behaviour
when queried and commanded through the public interfaces.
System developers, on the other hand, also need assurance that the system
interacts with its downstream dependencies as expected.
We can apply behavior testing similarly: by testing
the system via its public interfaces and downstream interactions,
we reduce the need to test the application layers in isolation.&lt;/p&gt;
&lt;p&gt;Just so we're clear, I'm not calling anyone to put the whole thing together
and test it on the launch pad. That's a recipe for disaster - remember what
happened to the
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/N1_(rocket)"&gt;Soviet N1 Moon rocket&lt;/a&gt;?&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Adverse characteristics of the large cluster of thirty engines and its complex
fuel and oxidizer feeder systems were not revealed earlier in development
because static test firings had not been conducted.
(&lt;a class="reference external" href="https://en.wikipedia.org/wiki/N1_(rocket)"&gt;Wikipedia&lt;/a&gt;)&lt;/blockquote&gt;
&lt;p&gt;Instead, I'm looking for relatively lightweight ways to test the entire
system, without going for a full end-to-end setup.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hexagonal-architecture-as-described-in-the-articles-series"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-2"&gt;Hexagonal architecture - as described in the articles series&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's recall the application and its architecture as described
in the articles series:&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/full-app.svg" style="width: 100%;" type="image/svg+xml"&gt;A hexagonal architecture application diagram&lt;/object&gt;
&lt;p class="caption"&gt;The example application is built using hexagonal architecture principles.
This is beyond what Alistair Cockburn describes in the original
&lt;a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture"&gt;&amp;quot;Hexagonal Architecture&amp;quot; article&lt;/a&gt;.
Cockburn only defines &lt;strong&gt;Ports&lt;/strong&gt;, &lt;strong&gt;Adapters&lt;/strong&gt;, &lt;strong&gt;Application&lt;/strong&gt; and their
interactions.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;Application&lt;/strong&gt; has a layered structure: the Core, which includes Domain
models and services; The driving/in/API (application programming interface)
and driven/out/SPI (service provider interface) ports for incoming and outgoing interactions;
and API and SPI adapters.&lt;/p&gt;
&lt;p&gt;Python wise:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The &lt;strong&gt;Domain model&lt;/strong&gt; consists of classes and methods which reflect
the real world domain rules. They are &amp;quot;pure&amp;quot; in nature, because
they don't have any outer world dependencies.&lt;/li&gt;
&lt;li&gt;We can think of &lt;strong&gt;API&lt;/strong&gt; and &lt;strong&gt;SPI ports&lt;/strong&gt; as delegates - basically, function signatures.
We can use Python Protocols or Abstract Base Classes to define them in
OOP-compatible way.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Application Services&lt;/strong&gt; implement API ports and orchestrate the flow
between domain models and SPI ports. They invoke SPI ports and can also
invoke other API ports when necessary.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;SPI adapters&lt;/strong&gt; implement SPI ports. SPI adapters are the bridges between
the application and downstream dependencies (databases, cashes, message queues,
file systems, other services etc.)&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;API adapters&lt;/strong&gt; connect the outer world to the application.
They receive commands and queries through different channels
(command line, http, RPC, message queue etc.) and invoke API ports.
The same API port can be invoked by many adapters - think of making the same
query via a command line, or via a RESTful HTTP interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="testing-the-application"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-3"&gt;Testing the application&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Martin Fowler speaks of &lt;strong&gt;&amp;quot;Solitary&amp;quot;&lt;/strong&gt; and &lt;strong&gt;&amp;quot;Sociable&amp;quot;&lt;/strong&gt; tests in the renowned
&lt;a class="reference external" href="https://martinfowler.com/bliki/UnitTest.html"&gt;article &amp;quot;Unit Test&amp;quot;&lt;/a&gt;.
Solitary tests mock the &lt;em&gt;direct dependencies&lt;/em&gt; of the component under test.
This is how I originally implemented tests in the
&amp;quot;Hexagonal Architecture with Django&amp;quot; project.
Tests like these run blazingly fast, but they only test the isolated behaviour
of a given component (like an HTTP controller, an application service,
or a database entities mapper) with fake downstream layer interactions.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/api-solitary-test.svg" style="width: 100%;" type="image/svg+xml"&gt;A diagram of solitary API test&lt;/object&gt;
&lt;p class="caption"&gt;A mockist-style HTTP adapter test.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Defining sociable tests is trickier:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;When xunit testing began in the 90's we made no attempt to go solitary unless
communicating with the collaborators was awkward
(such as a remote credit card verification system).&lt;/p&gt;
&lt;p&gt;I think that the term “unit testing” is appropriate because these tests
are tests of the behavior of a single unit.
We write the tests assuming everything other than that unit is working correctly.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Martin Fowler, &lt;a class="reference external" href="https://martinfowler.com/bliki/UnitTest.html"&gt;&amp;quot;Unit Test&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, in my perspective &lt;em&gt;a unit test is sociable when it verifies a unit of behaviour
across multiple components boundaries. In the verified interaction, at least
one direct dependency is not mocked, however the further dependencies can be mocked.&lt;/em&gt;&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/api-sociable-test.svg" style="width: 100%;" type="image/svg+xml"&gt;A diagram of sociable API test&lt;/object&gt;
&lt;p class="caption"&gt;A classical-style HTTP adapter test.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Finally, we utilise higher-level integration or end-to-end tests to verify the behaviour flow throughout the application and its dependencies.
Nowadays, tools such as &lt;a class="reference external" href="https://testcontainers.com/?language=python"&gt;Testcontainers&lt;/a&gt;
allow the isolation of these tests by spinning up the real databases, caches
and other dependencies for a short test lifetime.
However, this setup might be too resource-intensive, or other downstream dependencies,
that cannot be dockerised may need to come into play.
This leaves us with slow and fragile classical e2e tests in an
integration environment.&lt;/p&gt;
&lt;p&gt;What if we push sociable tests a bit further?
We can mock the layer which stands between our adapters and external dependencies.
This ensures that an API test flow passes forward
and back through the whole application
in a deterministic and isolated environment:&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/api-lightweight-integration-test.svg" style="width: 100%;" type="image/svg+xml"&gt;A diagram of a lightweight integration API test.&lt;/object&gt;
&lt;p class="caption"&gt;A lightweight integration test.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="architecture-revised"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-4"&gt;Architecture revised&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Software architecture is important because it allows us to independently evolve
different parts of the application and delay decisions.
In a way, architecture constrains us, but helps keep the system organised.&lt;/p&gt;
&lt;p&gt;My presentation of Hexagonal Architecture in this series of articles,
especially the testing part, was a bit bloated.
Alistair Cockburn
&lt;a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture"&gt;said nothing&lt;/a&gt;
about the application's (core) internals.
It's up to us whether we introduce &amp;quot;Service&amp;quot;, &amp;quot;Domain&amp;quot; or any other layer
or concept.
Just think: if an HTTP adapter handles a GET request to return
raw data from a single table in the database,
why even bother with &amp;quot;Service&amp;quot; and &amp;quot;Domain&amp;quot; layers
which would only perform data transformations?&lt;/p&gt;
&lt;p&gt;So, when it comes to lightweight integration testing,
we leave the application core as a black box,
and interact with adapters only.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/hexagonal-core.svg" style="width: 100%;" type="image/svg+xml"&gt;A hexagonal architecture application diagram&lt;/object&gt;
&lt;p class="caption"&gt;We are free to implement the application core in any way
when applying Hexagonal Architecture principles.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="lightweight-integration-tests-driven-development"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-5"&gt;Lightweight integration tests -driven development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A classical end-to-end test is a poor development driver.
It takes minutes, sometimes tens of minutes to run, often breaks,
has a complicated setup, and ... (your favourite fallacies here).
A lightweight integration test is somewhat better: it's fast
and fully under our control.
However, it rather drives adapters development,
&lt;strong&gt;NOT&lt;/strong&gt; the application core development.
It also requires a complicates setup, especially when it comes
to test doubles.&lt;/p&gt;
&lt;p&gt;Nevertheless, let's explore how such a test drives implementation.
What steps would we take?&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Pick a behaviour unit.&lt;/li&gt;
&lt;li&gt;Write a test for its API, asserting only the response.&lt;/li&gt;
&lt;li&gt;Write a minimal implementation to pass the test.&lt;/li&gt;
&lt;li&gt;If the behaviour is not pure and hits downstream dependencies,
write a test similar to (2), but &lt;strong&gt;this time verify the dependency interaction.&lt;/strong&gt;
Mock the dependencies and verify interactions via these mocks.&lt;/li&gt;
&lt;li&gt;Write a minimal implementation to pass the test.&lt;/li&gt;
&lt;li&gt;If any other tests break, fix them. &lt;strong&gt;Here, you enter
a recursion, starting at step 1 with a broken behaviour unit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Refactor. Remove duplication in application and tests code.
Apply Clean/Hexagonal architecture principles when necessary.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's walk through these steps by implementing the original
&amp;quot;Vote for an article&amp;quot; use case from scratch.
I &lt;strong&gt;will not&lt;/strong&gt; include implementation code here, just the tests code.
That's because the implementation stays the same, but the tests
are quite different.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="use-case-vote-for-an-article"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-6"&gt;Use case: Vote for an article&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let's recap the requirements for this use case:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Every article has a rating.&lt;/li&gt;
&lt;li&gt;Users can change an article's rating by either
&amp;quot;upvoting&amp;quot; or &amp;quot;downvoting&amp;quot; it.&lt;/li&gt;
&lt;li&gt;To vote on an article, a user's karma (their user rating)
needs to be higher than 5&lt;/li&gt;
&lt;li&gt;A user can only vote on each article once.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This translates into the following user story:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Given &lt;/span&gt;&lt;span class="nf"&gt;A registered user&lt;/span&gt;
&lt;span class="nf"&gt;      who can vote on articles.&lt;/span&gt;
&lt;span class="k"&gt;When &lt;/span&gt;&lt;span class="nf"&gt;they vote on an article.&lt;/span&gt;
&lt;span class="k"&gt;Then &lt;/span&gt;&lt;span class="nf"&gt;the article&amp;#39;s rating changes to reflect their vote.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="section" id="pick-a-behaviour-unit"&gt;
&lt;h3&gt;1. Pick a behaviour unit&lt;/h3&gt;
&lt;p&gt;We start with a happy case scenario.
Our TODO list looks like the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;### TODO&lt;/span&gt;

&lt;span class="k"&gt;* [ ]&lt;/span&gt; Test that &amp;quot;When user successfully votes for an article,
      the system responds with HTTP CREATED status and the vote details&amp;quot;.
&lt;span class="k"&gt;* [ ]&lt;/span&gt; Implement the view which handles voting for articles.
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="write-a-test-for-its-api"&gt;
&lt;h3&gt;2. Write a test for its API&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_when_user__successfully_votes_for_existing_article__system_returns_http_created_with_vote_details&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_article_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;DOWN&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;article_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;vote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DOWN&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here &lt;tt class="docutils literal"&gt;post_article_vote()&lt;/tt&gt; is a helper function which invokes the view via
&lt;tt class="docutils literal"&gt;APIRequestFactory&lt;/tt&gt;. This keeps the tests fast and limits the context to
the strictly necessary pieces.&lt;/p&gt;
&lt;p&gt;We run the test and it predictably fails.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="write-a-minimal-implementation-to-pass-the-test"&gt;
&lt;h3&gt;3. Write a minimal implementation to pass the test&lt;/h3&gt;
&lt;p&gt;The first round implementation which passes this test is amazingly simple:
the view just echoes the posted data.&lt;/p&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/api-sociable-test-echo.svg" style="width: 100%;" type="image/svg+xml"&gt;Echo HTTP request payload in response.&lt;/object&gt;
&lt;p class="caption"&gt;The minimal implementation which passes the test - echoing
POST payload back.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Is that it?
Does the API interaction fully describes the system behaviour?
Not really, because this behaviour is not pure, i.e. it has side effects,
and we need to store the vote somewhere.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="write-a-test-to-verify-downstream-interaction"&gt;
&lt;h3&gt;4. Write a test to verify downstream interaction&lt;/h3&gt;
&lt;div class="section" id="mocking-django-model-persistence"&gt;
&lt;h4&gt;Mocking Django model persistence&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;### TODO&lt;/span&gt;

&lt;span class="k"&gt;* [ ]&lt;/span&gt; Test that &amp;quot;When user successfully votes for an article,
      the system persists the vote&amp;quot;
&lt;span class="k"&gt;* [ ]&lt;/span&gt; Implement persisting the vote.
&lt;span class="k"&gt;* [X]&lt;/span&gt; Test that &amp;quot;When user successfully votes for an article,
      the system responds with HTTP CREATED status and the vote details&amp;quot;.
&lt;span class="k"&gt;* [X]&lt;/span&gt; Implement the view which handles voting for articles
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;We're using a database for storage, and Django provides out-of-the box tools
to run tests with a database backend.
You could use an in-memory SQLite, spin up a heavier DB in a Docker container,
or even use a shared database (oh the horror!).
But in my book, all these methods are rather integration tests, than unit tests,
because you are not really testing the application in isolation anymore.
The same applies to other integrations like message queues, event busses,
downstream services, file operations etc.&lt;/p&gt;
&lt;p&gt;What we can do though, is mock and spy on the persistence mechanisms that
are furthest to the right (from the application perspective) or at the very top
(from Django's perspective).
For instance, we can mock a model's &lt;tt class="docutils literal"&gt;save()&lt;/tt&gt; method and spy on it.
We can even create a pytest fixture like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;mock_persisting_article_vote&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;patch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ArticleVoteEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;save&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autospec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_mock_persisting_article_vote&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;mock&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;_mock_persisting_article_vote&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now we can spy on the &lt;tt class="docutils literal"&gt;save()&lt;/tt&gt; method calls and verify the instance details
passed as &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; argument.
But let's write a test first!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_when_user__successfully_votes_for_existing_article__system_persists_the_vote_in_the_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;post_article_vote&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;post_article_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# use the captured ``self`` value from ArticleVoteEntity().save()&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call_args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="figure align-center"&gt;
&lt;object data="https://zaurnasibov.com/articles/2025-02-08-hexarch-lightweight-integration-tests/mock-assert.svg" style="width: 100%;" type="image/svg+xml"&gt;Substitute Django database persistence mechanism with a mock.&lt;/object&gt;
&lt;p class="caption"&gt;Substituting Django database persistence mechanism with a mock in a unit test.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="write-a-minimal-implementation-to-pass-the-test-1"&gt;
&lt;h3&gt;5. Write a minimal implementation to pass the test&lt;/h3&gt;
&lt;p&gt;The implementation for this can be also naive - we can create and save
an &lt;tt class="docutils literal"&gt;ArticleVoteEntity&lt;/tt&gt; from the HTTP POST data.
A simple and well-known Django Rest Framework flow.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="refactor"&gt;
&lt;h3&gt;7. Refactor&lt;/h3&gt;
&lt;div class="section" id="mocks-are-for-humans-not-machines"&gt;
&lt;h4&gt;Mocks are for humans, not machines!&lt;/h4&gt;
&lt;p&gt;I personally find &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;spy.call_args[0][0]&lt;/span&gt;&lt;/tt&gt; very ugly and non-intuitive.
The fact that there is a comment explaining &lt;em&gt;what the line does&lt;/em&gt; is already
a code smell. How about writing a custom spy object which stores the saved
entity, so that we can get the captured entity via self-explanatory&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_when_user__successfully_votes_for_existing_article__system_persists_the_vote_in_the_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;saved_article_voted_entity&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;SaveArticleVoteEntitySpy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;saved_article_voted_entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ArticleVoteEntity&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;save_article_vote_entity_mock&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;entity&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;saved_article_voted_entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;


&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SaveArticleVoteEntitySpy&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;patch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ArticleVoteEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;save&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autospec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;save_mock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SaveArticleVoteEntitySpy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;save_mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;side_effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;spy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_article_vote_entity_mock&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;spy&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;_mock_persisting_article_vote&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="remove-duplication-in-tests"&gt;
&lt;h4&gt;Remove duplication in tests&lt;/h4&gt;
&lt;p&gt;You have probably noticed that the API response and Dependencies interaction
tests have the similar &lt;em&gt;Given&lt;/em&gt; and &lt;em&gt;When&lt;/em&gt; or &lt;em&gt;Arrange&lt;/em&gt; and &lt;em&gt;Act&lt;/em&gt; parts.
As a matter of fact, they &lt;strong&gt;should&lt;/strong&gt; have identical parts because
we're testing the same behaviour, just from different ends!&lt;/p&gt;
&lt;p&gt;Let's not repeat ourselves.
One way is to group the behaviour tests in a single class and
extract the &lt;em&gt;Arrange&lt;/em&gt; and &lt;em&gt;Act&lt;/em&gt; parts into their own fixtures
and methods. Now, this might be an overkill for a small setup, but here
is what I got in the end (&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog4/tests/test_myapp/application/test_api.py"&gt;spoiler alert!&lt;/a&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TestWhenUserSuccessfullyVotesForExistingArticle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;autouse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;arrange&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;given_a_user_who_can_vote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;given_no_existing_article_votes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;post_article_vote&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;given_a_user_who_can_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;given_no_existing_article_votes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;persisting_article_vote_spy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock_persisting_article_vote&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_article_vote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_article_vote&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;act&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_article_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_system_returns_http_created_with_vote_details&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;act&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CREATED&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;article_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;vote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DOWN&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_system_persists_the_vote_in_the_database&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;act&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;persisting_article_vote_spy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;saved_article_voted_entity&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;3f577757-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9af8961e-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;So far, so good, nothing is failing!
Our next step, however, is going to shake things up a little bit.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="use-case-only-existing-user-can-vote-for-an-article"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-7"&gt;Use case: Only existing user can vote for an article&lt;/a&gt;&lt;/h2&gt;
&lt;div class="section" id="pick-a-behaviour-unit-1"&gt;
&lt;h3&gt;1. Pick a behaviour unit&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;### TODO&lt;/span&gt;

&lt;span class="k"&gt;* [ ]&lt;/span&gt; Test that only existing user can vote for an article.
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;First, let's define an existing user as a record in the database.
Second, our current tests already cast a vote by the given &lt;tt class="docutils literal"&gt;user_id&lt;/tt&gt;.
So, no matter how we tweak the &amp;quot;Assert&amp;quot; and &amp;quot;Arrange&amp;quot; (or
&amp;quot;Then&amp;quot; and &amp;quot;When&amp;quot;) parts of the test, it will pass as long as we keep
those parts aligned.  We need a new test that &lt;em&gt;will&lt;/em&gt; break,
and guide implementation further:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;### TODO&lt;/span&gt;

&lt;span class="k"&gt;* [ ]&lt;/span&gt; &lt;span class="gs"&gt;**Test that a non-existing user can&amp;#39;t vote for an article.**&lt;/span&gt;
&lt;span class="k"&gt;* [ ]&lt;/span&gt; Test that only an existing user can vote for an article.
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="write-a-test-for-its-api-1"&gt;
&lt;h3&gt;2. Write a test for its API&lt;/h3&gt;
&lt;p&gt;Our system responds with &lt;tt class="docutils literal"&gt;HTTP NOT FOUND&lt;/tt&gt; in this case:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_when_voting__as_non_existing_user__system_returns_http_not_found_with_error_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;given_no_existing_users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;post_article_vote&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;given_no_existing_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;post_article_vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a3853333-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NOT_FOUND&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;detail&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;User &amp;#39;a3853333-0000-0000-0000-000000000000&amp;#39; not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Error&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This looks simple - we setup a system that doesn't have any users and then
try to vote. The system should respond with an error.
&lt;tt class="docutils literal"&gt;given_no_existing_user()&lt;/tt&gt; is a stub which returns no users when you try
to search for them. In Django terms, that's a temporary &lt;tt class="docutils literal"&gt;ObjectManager&lt;/tt&gt;,
with the necessary methods' stubs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUserEntityEmptyObjectManagerMock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&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="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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The fixture substitutes the object manager for a single test run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;given_no_existing_users&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;original_voting_user_entity_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_given_no_existing_user&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntityObjectManagerMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;_given_no_existing_user&lt;/span&gt;

    &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_voting_user_entity_manager&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;If we run the test, it fails because the logic implementation is missing.
To turn the test green, we need to query the database, check whether
a user exists, and return &lt;tt class="docutils literal"&gt;HTTP 404&lt;/tt&gt; otherwise.
Once that is ready, the last test passes,
however, &lt;strong&gt;the first two tests fail&lt;/strong&gt; when trying to access the database
since there is no way to set up existing users yet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Unexpected error occurred: Database access not allowed,
use the &amp;quot;django_db&amp;quot; mark, or the &amp;quot;db&amp;quot; or &amp;quot;transactional_db&amp;quot; fixtures
to enable it.
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="admonition important"&gt;
&lt;p class="first admonition-title"&gt;Important&lt;/p&gt;
&lt;p class="last"&gt;Think about it for a sec! How would you mock an existing user?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="fix-failing-tests"&gt;
&lt;h3&gt;6. Fix failing tests&lt;/h3&gt;
&lt;div class="section" id="mocking-existing-users"&gt;
&lt;h4&gt;Mocking existing users&lt;/h4&gt;
&lt;p&gt;We can mock existing users the same way we mocked &amp;quot;no existing users&amp;quot; - by
mocking the objects manager. First, we'll enable the manager to hold аnd return
a &lt;tt class="docutils literal"&gt;VotingUserEntity&lt;/tt&gt; stub:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUserEntityObjectManagerMock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;stub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;stub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stub&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get&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="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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stub&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stub&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;You can probably see where this is going, right?
All we need to add is a fixture builder:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;given_voting_user&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;original_voting_user_entity_manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_given_voting_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;karma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntityObjectManagerMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;karma&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;karma&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;_given_voting_user&lt;/span&gt;

    &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;original_voting_user_entity_manager&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="refactor-big"&gt;
&lt;h3&gt;7. Refactor BIG&lt;/h3&gt;
&lt;p&gt;Did you notice that we have already implemented a couple of behaviour units
inside a Django View, i.e. an API adapter? At this point we can start refactoring
the code by adding the necessary abstractions, service, and domain layers,
and moving Django model interaction code to SPI adapters.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;This is where things get a bit controversial.
Remember that tests are meant to guide development.
Hence, we must drive the development of the application core
via proper solitary and sociable tests!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;We are able do these refactorings because our tests cut through
all the application layers and verify the behavior on its edges.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="the-price-to-pay"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-8"&gt;The price to pay&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The lightweight integration tests let us quickly test application as a whole,
using mocks only at the system edges.
However, these mocks can become quite sophisticated because a single
use case triggered at the API often results in many downstream
interactions.
For example, imagine a scenario where the application returns
HTTP 409 - Conflict, when someone votes for an article a second time.
We'll need to mock &lt;tt class="docutils literal"&gt;User.objects&lt;/tt&gt; (a Django DB model ObjectManager)
to provide an existing user, as well as provide an existing article
via a mocked &lt;tt class="docutils literal"&gt;Article.objects&lt;/tt&gt; manager.&lt;/p&gt;
&lt;p&gt;At some point, the mocks can become &lt;em&gt;too&lt;/em&gt; sophisticated and create a mess
of their own.
That's when &lt;em&gt;real&lt;/em&gt; integration testing alternatives like in-memory SQLite,
or even &lt;a class="reference external" href="https://testcontainers.com/"&gt;Testcontainers&lt;/a&gt; start making more sense.
We may loose the rapid feedback of unit tests, but save ourselves a lot of
time spent on maintenance of messy test doubles.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="conclusion"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-9"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Solitary unit tests are excellent for developing individual components in isolation.
Sociable unit tests are a classical approach to testing pieces together, mocking
the complicated dependencies, for example, those which cross the I/O boundary.
Both solitary and sociable unit tests are my tools of choice
for test-driven development.&lt;/p&gt;
&lt;p&gt;Lightweight integration tests ensures that all components
work together correctly as a complete application,
while preserving the speed and flexibility of unit tests.
However, we need to invest significantly in edge mocks to emulate rightmost
interactions. Moreover, these tests primarily drive the implementation of
application edges - the adapters.&lt;/p&gt;
&lt;p&gt;Lightweight integration tests are a good alternative
to either missing integration tests or integration tests which require
an equally complicated setup.
They can be quite useful when refactoring a legacy system, that doesn't have
any tests. We can capture the interaction on the edges and ensure that
it doesn't change during development.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="acknowledgements"&gt;
&lt;h2&gt;&lt;a class="toc-backref" href="#toc-entry-10"&gt;Acknowledgements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once again, &lt;a class="reference external" href="https://github.com/jmp"&gt;Jarkko &amp;quot;jmp&amp;quot; Piiroinen&lt;/a&gt;
nudged me to dive deeper and challenge
my own understanding of the subject.
I'm very grateful for your input, Jarkko!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="architecture"/><category term="django"/><category term="hexagonal architecture"/><category term="lightweight integration tests"/><category term="programming"/><category term="python"/><category term="testing"/></entry><entry><title>Peopleware</title><link href="https://zaurnasibov.com/posts/2024/12/29/peopleware.html" rel="alternate"/><published>2024-12-29T22:20:00+02:00</published><updated>2024-12-29T22:20:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-12-29:/posts/2024/12/29/peopleware.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2024/12/29/peopleware.html"&gt;
&lt;img alt="Peopleware book cover" class="align-center" src="https://zaurnasibov.com/articles/2024-12-29-peopleware/peopleware-cover.webp" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Our industry, technological in nature, has far more sociological problems
and challenges. The tar pit swallows yet another project, not because we
couldn't figure out the technical parts, but because the people-oriented aspects
had the lowest priority.
&lt;strong&gt;Peopleware&lt;/strong&gt; is about teams and individuals, about the people of the office
- the &amp;quot;white collars&amp;quot;. It's about bosses and employees, leaders and managers.
It's about how, why, where, and what are our daily working activities about,
how every bit of surrounding environment affects them.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;A new, shiny office. Polished desktops. Comfortable chairs.
Floor-to-ceiling windows. A spacious kitchen.
You are moving here to make history! A new project is about to start, and your
organisation is going to expand. You have butterflies in your stomach.
Is everything going to be all right?
It feels like a good time to recap
&lt;strong&gt;Peopleware - Productive Projects and Teams&lt;/strong&gt;
by Tom DeMarco and Timothy Lister.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/posts/2024/12/29/peopleware.html"&gt;
&lt;img alt="Peopleware book cover" class="align-center" src="https://zaurnasibov.com/articles/2024-12-29-peopleware/peopleware-cover.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;Our industry, technological in nature, has far more sociological problems
and challenges. The tar pit swallows yet another project, not because we
couldn't figure out the technical parts, but because the people-oriented aspects
had the lowest priority.
&lt;em&gt;Peopleware&lt;/em&gt; is about teams and individuals, about the people of the office
- the &amp;quot;white collars&amp;quot;. It's about bosses and employees, leaders and managers.
It's about how, why, where, and what are our daily working activities about,
how every bit of surrounding environment affects them.&lt;/p&gt;
&lt;p&gt;Here is a hard truth about reviewing the book:
I couldn't make it! There are 39 chapters in &amp;quot;&lt;em&gt;Peopleware&lt;/em&gt;&amp;quot;.
And although they are grouped into six parts, and every chapter is rather short,
the breadth of topics is enormous!
The chapters are basically essays dedicated to a certain topic, and almost
every chapter could be a book of its own!&lt;/p&gt;
&lt;p&gt;If you think, that you know and have seen it all, did you give much though
to the office environment?
Did you know that people who program while listening to music easily miss
obvious solutions?
Or, how about hiring and letting people go? Is the cost of turnover as low
as you see it?
Do you remember to manage the obvious non-performance risks?
What it takes to grow a jelled team, which can read each other's minds
when working together?
And many more questions for which &lt;em&gt;Peopleware&lt;/em&gt; has answers
backed up with studies and the enormous experience of the authors.&lt;/p&gt;
&lt;p&gt;Every chapter is full of discoveries. I highly recommend this book for
leaders, managers and employees alike, because &lt;em&gt;Peopleware&lt;/em&gt; is about
betters ways that concern us all.&lt;/p&gt;
&lt;p&gt;If there was only a single advice from the book I could take, here it is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Hire the right people.&lt;/li&gt;
&lt;li&gt;Put them together into a fertile environment.&lt;/li&gt;
&lt;li&gt;Give room for learning, for trial and error.&lt;/li&gt;
&lt;li&gt;Help them grow towards company targets and their personal goals.&lt;/li&gt;
&lt;li&gt;And stay out of the way :)&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="management"/><category term="leadership"/><category term="office"/><category term="teams"/><category term="productivity"/></entry><entry><title>Testified Documentation</title><link href="https://zaurnasibov.com/posts/2024/09/29/testified-documentation.html" rel="alternate"/><published>2024-09-29T14:47:00+03:00</published><updated>2024-09-29T14:47:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-09-29:/posts/2024/09/29/testified-documentation.html</id><summary type="html">&lt;p class="first"&gt;It's hard to sell a software product - whether it's a library, a program,
or generally speaking, a system - if it doesn't come with a top-notch manual.
And keeping such manual up-to-date is not easy too.
Gojko Adzic's ideas of &lt;a class="reference external" href="https://zaurnasibov.com/posts/2023/02/21/specification_by_example_book_review.html"&gt;Living Documentation&lt;/a&gt; to the rescue, but unfortunately they are still far from being widely adopted.&lt;/p&gt;
&lt;p&gt;In this post I propose a different way of making Living Documentation -
by testifying its contents. Dive in to find out how!&lt;/p&gt;
&lt;a class="reference external image-reference last" href="https://zaurnasibov.com/posts/2024/09/29/testified-documentation.html"&gt;
&lt;img alt="Testified documentation diagram" class="align-center" src="https://zaurnasibov.com/articles/2024-09-29-testified-documentation/img/testified-documentation-horizontal.webp" /&gt;
&lt;/a&gt;
</summary><content type="html">&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;The manual is outdated unless you are continuously
building it alongside the application.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;&lt;a class="reference external" href="https://www.arhohuttunen.com"&gt;Arho Huttunen&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's hard to sell a software product - whether it's a library, a program,
or generally speaking, a system - if it doesn't come with a top-notch manual.
In my opinion, a good manual should describe
every aspect of the system, provide plenty of different high-level examples
and lower-level API specifications. It includes a changelog with
emphasised important and breaking changes, explains how to install, upgrades
and maintain the system.&lt;/p&gt;
&lt;p&gt;Keeping such documentation up-to-date is hard. Even when engineers who
work on the system take care of the manual, they easily miss some tricky aspects
or don't bother to document certain &amp;quot;obvious&amp;quot; behaviour.
It's even harder for technical writers who work in silos and don't know much
about the internals of the system, or don't fully understand the business case
covered by the product feature they are documenting.&lt;/p&gt;
&lt;div class="section" id="specification-by-example-and-cucumber"&gt;
&lt;h2&gt;Specification by Example and Cucumber&lt;/h2&gt;
&lt;p&gt;Gojko Adzic proposed the concept of Living Documentation in his renowned book
&lt;a class="reference external" href="https://zaurnasibov.com/posts/2023/02/21/specification_by_example_book_review.html"&gt;&amp;quot;Specification by Example&amp;quot;&lt;/a&gt;.
But Living Documentation doesn't come for free.
For a &lt;span class="strike"&gt;JIRA ticket&lt;/span&gt; a new feature description to become
an executable specification, one must first lay down a bridge between the human-friendly
narrative and the machine.&lt;/p&gt;
&lt;p&gt;For example: A fictional Flixnet movie streaming platform wants to notify the
customers that their subscriptions are about to expire.
After user mapping sessions, the stakeholders wrote down the following
specification expressed in Gherkin/Cucumber syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Feature:&lt;/span&gt;&lt;span class="nf"&gt; Remind a customer about an expiring subscription&lt;/span&gt;

&lt;span class="nf"&gt;  The customer might forget that their Flixnet subscription is expiring.&lt;/span&gt;
&lt;span class="nf"&gt;  We want to retain the customer by reminding them about the expiring subscription&lt;/span&gt;
&lt;span class="nf"&gt;  and providing an easy way to remain subscribed.&lt;/span&gt;
&lt;span class="nf"&gt;  We will notify the customer only once, 3 days before the subscription expires,&lt;/span&gt;
&lt;span class="nf"&gt;  so that the customer is not annoyed.&lt;/span&gt;

&lt;span class="nf"&gt;  &lt;/span&gt;&lt;span class="k"&gt;Scenario:&lt;/span&gt;&lt;span class="nf"&gt; An active customer whose subscription expires in 3 days gets a notification&lt;/span&gt;
&lt;span class="k"&gt;    Given &lt;/span&gt;&lt;span class="nf"&gt;an active customer&lt;/span&gt;
&lt;span class="nf"&gt;    &lt;/span&gt;&lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="nf"&gt;their subscription expires in &lt;/span&gt;&lt;span class="s"&gt;3&lt;/span&gt;&lt;span class="nf"&gt; days&lt;/span&gt;
&lt;span class="nf"&gt;    &lt;/span&gt;&lt;span class="k"&gt;And &lt;/span&gt;&lt;span class="nf"&gt;we have not sent them a reminder yet&lt;/span&gt;
&lt;span class="nf"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Then &lt;/span&gt;&lt;span class="nf"&gt;send the customer a reminder&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;How do we organise the document that incorporates
this specification? Should it have a link to the specification? Or take
some of its parts, like the feature name and description? Remember that Gherkin
pays no attention to those, they are for the reader's convenience only.
With some effort, it is possible to program &lt;a class="reference external" href="https://docutils.sourceforge.io"&gt;docutils&lt;/a&gt;
or &lt;a class="reference external" href="https://myst-parser.readthedocs.io/en/latest/"&gt;MyST&lt;/a&gt;
directive to include the specification into a Markdown file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gu"&gt;### User notifications and reminders&lt;/span&gt;

We send our users notifications on certain occasions. They are listed below:

```{specification}
:feature: Remind a customer about expiring subscription
:include-description:
```

...
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Coupled with the ability to check specification execution (aka tests) results&lt;/em&gt;,
this could provide a living documentation!
It's quite close, to what Gojko Adzic described
in his 10-years-later aftermath &lt;a class="reference external" href="https://gojko.net/2020/03/17/sbe-10-years.html"&gt;article&lt;/a&gt;
written in 2020. He noticed, that with then-available breed of
Given-When-Then tools, the most effective solution was converting
the specification files into something nicer and easier to read
and then publishing a read-only version somewhere outside the version
control system.&lt;/p&gt;
&lt;p&gt;The sad part is that specifications written in Gherkin and executed via Cucumber
are largely abused. Aslak Hellesøy wrote in 2014 that Cucumber was
&lt;a class="reference external" href="https://cucumber.io/blog/collaboration/the-worlds-most-misunderstood-collaboration-tool/"&gt;largely misunderstood&lt;/a&gt;.
Cucumber is first a formost a &lt;em&gt;collaboration tool&lt;/em&gt; that aims to bring a
common understanding to software teams - across roles. It is not a testing tool
for QA to write end-to-end tests on an existing implementation.
I witnessed horrible Cucumber misuse: specifications written weeks after
implementation got integrated; Specifications which have only technical terms
and describe implementation details instead of business rules;
Specifications meaningless and repetitive, such as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;Given &lt;/span&gt;&lt;span class="nf"&gt;a user&lt;/span&gt;
&lt;span class="k"&gt;When &lt;/span&gt;&lt;span class="nf"&gt;user logs in&lt;/span&gt;
&lt;span class="k"&gt;Then &lt;/span&gt;&lt;span class="nf"&gt;user is logged in&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;In other words, no one benefits from including &lt;em&gt;bad&lt;/em&gt; Gherkin specification
details into a manual. And the tooling does not exist yet, anyway.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="testified-documentation-1"&gt;
&lt;h2&gt;Testified Documentation&lt;/h2&gt;
&lt;p&gt;Back to square one - how else to ensure that the behaviour described in the
release manual aligns with the released program behaviour?&lt;/p&gt;
&lt;p&gt;A simple idea struck me in September 2024.
What if we use something that is widely adopted by software engineers?
That is - the output of automated tests: unit, behaviour,
end-to-end - all of them that run on every build of the system.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2024-09-29-testified-documentation/img/testified-documentation.svg"&gt;
&lt;img alt="Testified documentation diagram" class="align-center" src="https://zaurnasibov.com/articles/2024-09-29-testified-documentation/img/testified-documentation.webp" style="width: 80%;" /&gt;
&lt;/a&gt;
&lt;p&gt;Test automation tooling is widely available and is quite stable for popular
programming platforms.
Moreover, test runners usually support a common
&lt;a class="reference external" href="https://github.com/testmoapp/junitxml"&gt;JUnit XML&lt;/a&gt; output format.
For example, here is the formatted report of two executed smoke tests:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;testsuites&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;testsuite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pytest&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;errors=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;failures=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;skipped=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;tests=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;time=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.041&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;timestamp=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;2024-09-29T14:19:49.292476+03:00&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;hostname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;z&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;testcase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;classname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test.test_smoke&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test_smoke&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;time=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.001&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;testcase&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;classname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test.test_smoke.TestBigSmoke&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;test_big_smoke&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;time=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;0.000&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/testsuite&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/testsuites&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now imagine that for every paragraph in documentation file, we include a
directive that checks whether certain test cases passed successfully.
The results are invisible for the end user,
it's intended for developers and copywriters:
if any of the required tests fails, documentation won't build.&lt;/p&gt;
&lt;p&gt;It's nothing new though:
some products already utilize testifying artifacts produced by test automation
in documentation.
For example, visual tests make screenshots, and the documentation embeds them
as example images.&lt;/p&gt;
&lt;p&gt;I quickly assembled a small PoC for &lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt;
- a tool widely used to write manuals for Python libraries and programs.
Here, I included a test name as a role
(yes, it should have been a directive ;-):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;This is a documentation for the &amp;quot;Spectest&amp;quot; library.

Spectest starts with a simple smoke test. &lt;span class="na"&gt;:spectest:&lt;/span&gt;&lt;span class="nv"&gt;`test.test_smoke.test_smoke`&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The build reads test results from the XML above, passes successfully and
outputs a Sphinx-based HTML manual.
However, if we simulate a test failure by changing the verified name to
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:spectest:`test_ABCD`&lt;/span&gt;&lt;/tt&gt;, the build breaks along:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;/home/zaur/.../index.rst:13: ERROR: TEST test_ABCD not found [docutils]
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;That's the idea in a nutshell. To me it sounds &lt;em&gt;technically&lt;/em&gt; simple enough to get
implemented for any extensible documentation generator.&lt;/p&gt;
&lt;p&gt;The devil is however, in the details.
Testified documentation won't work well unless you have thorough behavior tests.
That doesn't imply E2E tests at all! (I profess keeping those to a bare minimum.)
Rather, have a suite of fast &lt;a class="reference external" href="https://martinfowler.com/bliki/UnitTest.html"&gt;sociable tests&lt;/a&gt;
that verify system behaviour and utilize stubs and mocks for external dependencies.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="feedback"&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;Rainbows and unicorns :) I would love to hear your thoughts on this topic
and include them here. I am a lucky guy who can share the
wildest ideas with my colleagues and friends and get honest feedback.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/jmp"&gt;Jarkko 'jmp' Piiroinen&lt;/a&gt; had a very
valid and cool-minded point: there is zero incentive to make this kind of
documentation-to-test-results bindings if the target audience doesn't care
about full-fledged product documentation in the first place.&lt;/p&gt;
&lt;p&gt;Seems to be the case, when a system is small enough to fit into
product team members heads,
and especially when the external interfaces are already documented
in a form of specification, like OpenAPI spec.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.arhohuttunen.com"&gt;Arho Huttunen&lt;/a&gt; reminded that
Cucumber is not the only tool for Specification by Example and Living Documentation.
Uncle Bob's &lt;a class="reference external" href="https://fitnesse.org"&gt;FitNesse&lt;/a&gt; was there already in 2002!
There are also &lt;a class="reference external" href="https://concordion.org"&gt;Concordion&lt;/a&gt;, &lt;a class="reference external" href="https://serenity-bdd.github.io"&gt;Serentiy&lt;/a&gt;, and most likely, others.
We also discussed that for code examples in documentation, tools like
&lt;a class="reference external" href="https://www.sphinx-doc.org/en/master/usage/extensions/doctest.html"&gt;Doctest&lt;/a&gt;
which allow executing and testing their output during manual generation phase
are even more useful.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="python"/><category term="documentation"/><category term="tests"/><category term="specification"/><category term="BDD"/><category term="collaboration"/><category term="cucumber"/></entry><entry><title>The dark patterns of seat selection in Turkish Airlines</title><link href="https://zaurnasibov.com/posts/2024/08/17/dark-patterns-of-seat-selection-in-turkish-airlines.html" rel="alternate"/><published>2024-08-17T20:44:00+03:00</published><updated>2024-08-17T20:44:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-08-17:/posts/2024/08/17/dark-patterns-of-seat-selection-in-turkish-airlines.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2024/08/17/dark-patterns-of-seat-selection-in-turkish-airlines.html"&gt;
&lt;img alt="Dark Turkish airlines logo" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/turkish-black-logo.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;Turkish Airlines is our first choice when it comes to flying to Azerbaijan from
Finland. It’s not the cheapest, but the service is great. You get good food
even in economy class, and there is an entertainment system with a broad selection
of movies to keep you and the kids busy. The baggage allowance is huge - 30kg
for check-in and the standard 8+kg for carry-on, although I’ve never seen them
put the carry-on baggage on scales.&lt;/p&gt;
&lt;p class="last"&gt;So, what’s all the fuss about?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Turkish Airlines is our first choice when it comes to flying to Azerbaijan from
Finland. It’s not the cheapest, but the service is great. You get good food
even in economy class, and there is an entertainment system with a broad selection
of movies to keep you and the kids busy. The baggage allowance is huge - 30kg
for check-in and the standard 8+kg for carry-on, although I’ve never seen them
put the carry-on baggage on scales.&lt;/p&gt;
&lt;p&gt;So, what’s all the fuss about?&lt;/p&gt;
&lt;img alt="Dark Turkish airlines logo" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/turkish-black-logo.webp" /&gt;
&lt;div class="section" id="ticket-prices-gone-wrong"&gt;
&lt;h2&gt;Ticket prices gone wrong&lt;/h2&gt;
&lt;p&gt;It started in mid-spring when we were checking ticket prices for Helsinki-Baku flights.
The figures were crazy, to say the least. Since we were also planning
a summer trip to Estonia, we decided to check the price from Tallinn.
Bingo! Twice as cheap. There are roughly 100 km between Tallinn
and Helsinki (Vantaa) airports. The distance doesn’t justify it.
Helsinki airport tariffs are certainly higher than Tallinn’s, but not that much!
So, the good old supply and demand: if Turkish Airlines can sell the tickets
for that price, why go lower? It’s summer season after all,
and Finns are rushing to warm countries.&lt;/p&gt;
&lt;p&gt;This ticket price talk is rather a rant. After all, the route is not monopolized;
one can fly, for example, Air Baltic when on a strict budget. However,
I wanted to emphasize that the tickets are not cheap, and considering
all the services included, the dark patterns are not something you would expect.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="seat-selection-gets-weird"&gt;
&lt;h2&gt;Seat selection gets weird&lt;/h2&gt;
&lt;p&gt;For years, we had a default seat arrangement where either all of us sat together,
or (after our youngest daughter was born) 3 + 1, making it possible for both kids
to sit with either mom or dad.&lt;/p&gt;
&lt;p&gt;But on the flight from Tallinn to Istanbul (our first leg), the seats
were split as 2 + 2. This was on an Airbus 321 (or Boeing 737, I can’t remember exactly)
where economy class has a 3 + 3 seat configuration.&lt;/p&gt;
&lt;p&gt;Well, the kids have grown up enough to sit alone with either parent,
so it’s truly not a big deal, right?
But that was the first subconscious bell - have Turkish Airlines updated their
algorithms?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="seat-selection-gets-worse"&gt;
&lt;h2&gt;Seat selection gets worse&lt;/h2&gt;
&lt;p&gt;Two days before going back to Finland, we got an email:&lt;/p&gt;
&lt;img alt="Your seat have been changed screenshot" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/your-seat-have-been-changed-screenshot.webp" /&gt;
&lt;p&gt;The all-caps subject is certainly emphasizing. What's inside?&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Dear ZAUR NASIBOV&lt;/p&gt;
&lt;p&gt;Your seat selection on the 10 AUGUST TK0339 Baku (GYD) -Istanbul,Istanbul (IST)
has been changed to 11F due to operational reasons.&lt;/p&gt;
&lt;p&gt;For details and seat transactions to your *** reservation, you may visit our
MOBILE app / WEBSITE Air.tk/manage-booking.&lt;/p&gt;
&lt;p&gt;Thank you for your undestanding.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Who said that I am &lt;em&gt;undestanding&lt;/em&gt;? Because I was not understanding,
neither I did want to. Upon checking the seats I saw this:&lt;/p&gt;
&lt;img alt="New seats" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/seats-changed.webp" style="width: 40%;" /&gt;
&lt;p&gt;What the... Has someone reserved both &lt;tt class="docutils literal"&gt;D&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;E&lt;/tt&gt; seats in row 10 or 11?
Perhaps all the seat pairs and triplets are taken, and there is no way to
accommodate us closer to each other? Let's check the rows at the tail:&lt;/p&gt;
&lt;img alt="Empty seats at the tail" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/empty_tail_seats.webp" style="width: 40%;" /&gt;
&lt;p&gt;So many unreserved seats! Yet, instead of keeping us together ten rows
further to the tail, the algorithm decides to split us in the most annoying way.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="support-can-t-do-anything"&gt;
&lt;h2&gt;Support can't do anything&lt;/h2&gt;
&lt;p&gt;I had some hope that support might help with the problem. Although caring, the
operator could do nothing, since the seat reservations were not paid for -
they were &amp;quot;randomly assigned&amp;quot;. According to the operator, I could either
pay for the desired seats or... request better seats while checking in at the
airport.&lt;/p&gt;
&lt;p&gt;Frequent fliers know too well that nowadays the chances of ending up at the
very tail of a plane are increasingly high when checking in at the airport.
Usually, passengers check in via airline apps hours before the flight
to secure their seats. And just few years ago, selecting seats while checking
in was free of charge, at least with Turkish airlines. Not anymore.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="five-stages-of-grief"&gt;
&lt;h2&gt;Five stages of grief&lt;/h2&gt;
&lt;p&gt;Twenty four hours before the flight, I am awake early to check in via the app.
&lt;em&gt;Sure, you can pick the seat! Only 14 Euros per passenger!&lt;/em&gt;&lt;/p&gt;
&lt;img alt="Selecting seats is not free anymore" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/check-in-seats.webp" style="width: 40%;" /&gt;
&lt;p&gt;Denial, anger, bargaining, depression, and acceptance - all happening within
a blink of an eye. It is not about the money; 14 Euros is what lunch costs
in Finland. It was really a question of principle. First, they spread people
from a group (read: family members) across the rows, and now they make us pay
to get back together. And you know what? That’s ingenious!
Because I paid that money so that we don’t end up scattered even more
or at the last rows in the tail. Bravo, Turkish Airlines, you’ve discovered
a dark well of gold!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bad-luck"&gt;
&lt;h2&gt;Bad luck?&lt;/h2&gt;
&lt;p&gt;Perhaps I’m wrong. Perhaps it’s just bad luck. On the second leg of the journey,
our seats were on the same row: &lt;tt class="docutils literal"&gt;B, C, D, E&lt;/tt&gt;. Imagine my surprise when the
neighboring passengers from seats &lt;tt class="docutils literal"&gt;A&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;F&lt;/tt&gt; asked to change places
because they were a mother and daughter flying together!
(Note: This is a crafted screenshot; I didn’t take a screenshot of these seats back then).&lt;/p&gt;
&lt;img alt="Our seats on the second leg" class="align-center" src="https://zaurnasibov.com/articles/2024-08-17-dark-patterns-of-seat-selection-at-turkish-airlines/seats-second-leg.webp" style="width: 40%;" /&gt;
&lt;/div&gt;
&lt;div class="section" id="aftermath"&gt;
&lt;h2&gt;Aftermath&lt;/h2&gt;
&lt;p&gt;Will I stop flying Turkish Airlines? Let’s see what next year brings :)
As a passenger, I despise dark patterns like this and would rather pay extra
from the start to have a pleasant experience, instead of getting
“YOUR SEAT HAS BEEN CHANGED!11!!!11” emails.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="flying"/><category term="turkish-airlines"/><category term="dark-patterns"/></entry><entry><title>Building Microservices - more than just another "microservices book"</title><link href="https://zaurnasibov.com/posts/2024/07/09/building-microservices-more-than-just-another-microservices-book.html" rel="alternate"/><published>2024-07-09T18:32:00+03:00</published><updated>2024-07-09T18:32:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-07-09:/posts/2024/07/09/building-microservices-more-than-just-another-microservices-book.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2024/07/09/building-microservices-more-than-just-another-microservices-book.html"&gt;
&lt;img alt="Building Microservices book cover" class="align-center" src="https://zaurnasibov.com/articles/2024-07-09-building-microservices/building-microservices-cover.webp" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;While &amp;quot;Building Microservices&amp;quot; is not an encyclopedia, it definitely
feels like one.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Finally! Hundreds of pages dedicated to microservices have been transferred to my brain.
Even if only a tenth of what I read stays with me, then Sam Newman has definitely succeeded.
&amp;quot;Building Microservices&amp;quot; is enormous - not just in size (there are
certainly bigger books!) but in the vast range of topics it covers.
What some people think of as &amp;quot;Microservices&amp;quot; might only be the summit of
an enormous &amp;quot;MICROSERVICES&amp;quot; mountain.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/posts/2024/07/09/building-microservices-more-than-just-another-microservices-book.html"&gt;
&lt;img alt="Building Microservices book cover" class="align-center" src="https://zaurnasibov.com/articles/2024-07-09-building-microservices/building-microservices-cover.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;This book is about the topography of that mountain.
It doesn't delve too deeply into every aspect, but it provides an overview,
gives directions, helps with navigation, highlights pitfalls,
and suggests proven routes - all to ensure that you can reach the summit safely.
Like any mountain climb, adopting microservices comes with decisions to make and trade-offs to take.&lt;/p&gt;
&lt;p&gt;Newman starts the book with the fundamentals:
What are microservices?
How do we model microservices in relation to the problem we are solving
(i.e., the product we are building)?
How do we split an existing monolithic solution into microservices?&lt;/p&gt;
&lt;p&gt;He then moves on to the technical aspects: communication, security,
building and testing, monitoring, and even front-end development.&lt;/p&gt;
&lt;p&gt;The last part is about us, the people who build microservices.
Once again, we learn how important Conway's Law is, what the optimal organizational
structure to support microservices development looks like,
and the role of architects in all of this.&lt;/p&gt;
&lt;p&gt;I was very excited to read the book.
I loved that the author provided enough information to understand the topics
and left breadcrumbs, referencing books, articles, and videos so that one
can delve deeper and learn more.
&amp;quot;Building Microservices&amp;quot; will find its audience among architects,
novice and experienced backend developers alike. I highly recommend it.&lt;/p&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="microservices"/><category term="architecture"/></entry><entry><title>Teams Topologies - Book Review</title><link href="https://zaurnasibov.com/posts/2024/03/23/teams-topologies-book-review.html" rel="alternate"/><published>2024-03-23T21:42:00+02:00</published><updated>2024-03-23T21:42:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-03-23:/posts/2024/03/23/teams-topologies-book-review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2024/03/23/teams-topologies-book-review.html"&gt;
&lt;img alt="&amp;quot;Teams Topologies book cover&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2024-03-23-teams-topologies/teams-topologies-cover.webp" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Conway’s Law states that systems are designed to mirror the communication
structures of the organizations that create them. How, then, can we
shape an organization to produce the desired system design? Let's
find out &amp;quot;Team Topologies: Organizing Business and Technology Teams
for Fast Flow&amp;quot; by Matthew Skelton and Manuel Pais.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Are you familiar with the exiting feeling of making a discovery?
Butterflies in your stomach, intermittent breathing, galvanized palms?
Every chapter draws a &amp;quot;&lt;em&gt;WOW!&lt;/em&gt;&amp;quot;, every page turns into a vivid picture
in your imagination.
That is &amp;quot;Team Topologies&amp;quot; -  a book about systems architecture.
This may come as a surprise, since the title clearly states otherwise.
It's also a book about teams interactions and organizational design.&lt;/p&gt;
&lt;img alt="&amp;quot;Teams Topologies book cover&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2024-03-23-teams-topologies/teams-topologies-cover.webp" /&gt;
&lt;p&gt;Part I - &lt;em&gt;Teams As the Means of Delivery&lt;/em&gt;.
Matthew Skelton and Manuel Pais dedicate the early
chapters of the book to show how organizational structure affects
the system design. This effect is nowadays known as &amp;quot;Conway's law&amp;quot;,
which originates from Mel Conway's 1968 paper &amp;quot;How Do Committees Invent&amp;quot;:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Organizations which design systems ... are constrained to produce designs
which are copies of the communication structures of these organizations.&lt;/blockquote&gt;
&lt;p&gt;It is a scary discovery. It means that organizational structure prevails
over system architecture, unless the structure is made to support the
desired architecture. If the former and the latter are in conflict, one
of them has to change. Which one? If the desired architecture is the target,
there isn't much to change about it. This leaves us with the organizational
structure.&lt;/p&gt;
&lt;p&gt;But before diving into the structure, the organization needs to have team-first
mindset. In the book, a team is a stable group of five to nine people who
work toward a shared goal as a unit. The team is the smallest entity of delivery
within the organization. An organization should never assign work to individuals;
only to teams.&lt;/p&gt;
&lt;p&gt;How can an organization improve team performance?
The team should be long-lived and stable, of relatively small size (as stated above).
The team should own the software while being able to limit its cognitive load.
The organization should reward the team, not individuals.
Last but not the least: the team members should develop a team-first mindset,
prioritizing team goals and all required activities that help achieve these goals.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Organizations must design teams intentionally by asking these questions:
Given our skills, constraints, cultural and engineering maturity, desired
software architecture, and business goals, which team topology will help
us deliver results faster and safer? How can we reduce or avoid handovers
between teams in the main flow of change? Where should the boundaries be
in the software system in order to preserve system viability and encourage
rapid flow? How can our teams align to that?&lt;/blockquote&gt;
&lt;p&gt;The answers to these questions are found in
Part II - &lt;em&gt;Team Topologies that Work for Flow&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The authors start by examining team anti-patterns, such as
frequently shuffling team members and ad-hoc or reactive
team design. A team that has grown too large may be split without clear
boundaries. A dedicated DBA team might be created after a software crash
in production due to poor database handling. These situation certainly
require action, but &amp;quot;the most natural solution&amp;quot; might slow down delivery and
weaken the autonomy of teams.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
In order to be as effective as possible, we need to consciously design
our teams rather than merely allow them to form accidentally or haphazardly.
We call these consciously designed team structures &lt;strong&gt;team topologies&lt;/strong&gt;,
a term that acknowledges that teams should be deliberately “placed”
into organizations while also referring to the boundary of responsibility
of each team.&lt;/blockquote&gt;
&lt;p&gt;A high-performing team takes responsibility and the ownership of the features
they develop - from design all the way to production. Here, &lt;em&gt;production&lt;/em&gt; means
monitoring feature usage and performance, rather than handing it over to an Ops team.
Such a team is cross-functional and equipped with all necessary skills
to design, develop, test, deploy and monitor application usage and performance.
To maintain a rapid flow, the team remains autonomous, ideally utilizing non-blocking
external dependencies in the form of self-services developed and maintained
by other teams.&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2024-03-23-teams-topologies/feedback-from-production.svg"&gt;
&lt;img alt="&amp;quot;Feedback from production to different development stages maintained by the same team&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2024-03-23-teams-topologies/feedback-from-production.png" style="width: 100%;" /&gt;
&lt;/a&gt;
&lt;hr class="docutils" /&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Perfection is achieved, not when there is nothing more to add, but
when there is nothing left to take away.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Antoine de Saint-Exupéry, Airman's Odyssey&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Skelton and Pais reduce the number of team variations to four fundamental
team topologies:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;Stream-aligned team&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Enabling team&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Complicated-subsystem team&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Platform team&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The authors argue that these are the only topologies
necessary to build and run modern software systems. Limiting to these
four team types acts as a powerful template for effective organization design,
especially when combined with well-defined software boundaries and efficient
team interactions.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;stream-aligned&lt;/strong&gt; team is the primary team type in an organization, and
the purpose of the other fundamental team topologies. A &lt;em&gt;stream&lt;/em&gt; represents the
continuous flow of work aligned to a business domain or organizational
capability. The team is empowered to build and deliver customer or user
value as quickly, safely, and independently as possible.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;enabling team&lt;/strong&gt; assists stream-aligned teams in acquiring necessary skills
and knowledge, setting up pipelines, adopting tools and solving engineering problems
in unfamiliar environments. Enabling teams have a strongly collaborative nature;
they thrive to understand the problems and shortcomings of stream-aligned
teams in order to provide effective guidance.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;complicated-subsystem&lt;/strong&gt; team is responsible for building and maintaining
a part of the system that relies heavily on specialized knowledge.
This is to such an extent that most team members must be specialists in that particular
area to understand and maintain the subsystem effectively.
Examples of complicated subsystems might include a mathematical model,
a mainframe module, a voice recognition algorithm, and so on.&lt;/p&gt;
&lt;p&gt;The purpose of the &lt;strong&gt;platform team&lt;/strong&gt; is to enable stream-aligned team to deliver
their work autonomously. It provides internal services to reduce the cognitive
load that would otherwise be required from stream-aligned teams to develop these underlying
services. Examples of these services include: continuous integration (CI),
code registries, repository hosting, databases, deployment, monitoring,
logging aggregation and so on.&lt;/p&gt;
&lt;p&gt;Based on reports from successful organizations, the ratio of stream-aligned teams
to other types of teams should be between approximately 6:1 and 9:1.&lt;/p&gt;
&lt;p&gt;How should stream-aligned teams divide responsibilities?
The authors advice breaking down the system, so that the resulting parts
can evolve as independently as possible. Consequently, teams assigned to these
parts will experience greater autonomy and ownership over them.&lt;/p&gt;
&lt;p&gt;It is also essential to consider the teams dynamics when splitting a monolith.
Splitting a monolithic application into autonomous services that need
to be released and deployed together is merely creating a
&amp;quot;distributed monolith&amp;quot; with tightly coupled pieces.
Microservices sharing a database, monolithic world models with similar domain
language and representation across different formats, or even a single office
layout for all the teams, can all contribute to a distributed monolith.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;Now that the reader is familiar with the four fundamental team topologies,
Skelton and Pais discuss how teams interact and when to change the teams
and their interactions. Well-defined interactions are key to effective
teams, and the authors outline three essential ways teams can and should interact:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Collaboration: working closely together with another team&lt;/strong&gt;.
Imagine two or more teams coming together to solve a problem that requires
competences from all of them. Their collaboration is rapid; they quickly
make discoveries and share knowledge, experiment and prototype solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X-as-a-Service: consuming or providing something with minimal collaboration&lt;/strong&gt;.
This interaction is ideal when a team needs to focus on its tasks and
consume the necessary services - from CI/CD infrastructure to upstream
production API services - without being involved in their development and
maintenance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Facilitating: helping (or being helped by) another team to clear impediments&lt;/strong&gt;.
When a team lacks certain competences, a facilitating team can save the
day by coaching and providing help. This is the main interaction mode for
Enabling teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last chapter of the book - &lt;strong&gt;Evolve Team Structures with Organizational Sensing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;As Frederic Brooks mentioned in &amp;quot;Mythical Man-Months&amp;quot;:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Conway goes on to point out that the organization chart
will initially reflect the first system design, which is almost surely
not the right one. If the system design is to be free to change, the
organization must be prepared to change.&lt;/blockquote&gt;
&lt;p&gt;The software design must align with the way in which teams communicate;
otherwise, it is doomed to fail. The methods of communication evolve as
the system and the organization matures. What begins as collaboration eventually
becomes part of platform services with strict boundaries. Stream-aligned teams
seek help from Enabling teams when necessary or provide assistance to other teams
upon request.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;I tried very hard to distill the essential ideas of the book into this small review
to get you interested in reading it. As you can imagine, there is so much more!
If you are ever involved in designing systems architecture that requires
the interaction of many teams, this book is a must-read.&lt;/p&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="architecture"/><category term="teams"/><category term="software development"/></entry><entry><title>The Mythical Man-Months - thoughts</title><link href="https://zaurnasibov.com/posts/2024/03/19/mythical-man-months.html" rel="alternate"/><published>2024-03-19T21:42:00+02:00</published><updated>2024-03-19T21:42:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2024-03-19:/posts/2024/03/19/mythical-man-months.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2024/03/19/mythical-man-months.html"&gt;
&lt;img alt="&amp;quot;Then Mythical Man-Months&amp;quot; by Frederic Broogks book cover" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/mythical-man-months-book-cover.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;As the year 2023 was coming to an end, I finally had some time to recap
&lt;strong&gt;&amp;quot;The Mythical Man-Month: Essays on Software Engineering&amp;quot;&lt;/strong&gt;
by Fred Brooks. The book talks about software development fallacies from
software engineering and project management perspectives.
However this is not &amp;quot;yet another book&amp;quot;. It was first published in 1975,
nearly fifty years ago! So much changed since 1975, and yet, so little!
It's unbelievable that today we are still struggling with the problems
that haunted us in the age of mainframes.&lt;/p&gt;
&lt;p class="last"&gt;You smile a lot as you read the book. Programming with punch cards?
A big fat machine with only 2 MB of RAM? Software documented on paper?
Sure, things were different back then. But there are so many similarities!
Instead of reviewing the book, I'd prefer to study these similarities,
draw parallels, and find out whether things have changed for the better.&lt;/p&gt;
</summary><content type="html">&lt;img alt="&amp;quot;Then Mythical Man-Months&amp;quot; by Frederic Brooks book cover" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/mythical-man-months-book-cover.webp" /&gt;
&lt;p&gt;As the year 2023 was coming to an end, I finally had some time to recap
&lt;strong&gt;&amp;quot;The Mythical Man-Month: Essays on Software Engineering&amp;quot;&lt;/strong&gt;
by Fred Brooks. The book talks about software development fallacies from
software engineering and project management perspectives.
However this is not &amp;quot;yet another book&amp;quot;. It was first published in 1975,
nearly fifty years ago! So much changed since 1975, and yet, so little!
It's unbelievable that today we are still struggling with the problems
that haunted us in the age of mainframes.&lt;/p&gt;
&lt;p&gt;You smile a lot as you read the book. Programming with punch cards?
A big fat machine with only 2 MB of RAM? Software documented on paper?
Sure, things were different back then. But there are so many similarities!
Instead of reviewing the book, I'd prefer to study these similarities,
draw parallels, and find out whether things have changed for the better.&lt;/p&gt;
&lt;div class="section" id="the-tar-pit"&gt;
&lt;h2&gt;1 - The Tar Pit&lt;/h2&gt;
&lt;p&gt;Programming is joyful. Every time our program behaves as we intended, it's
like a small masterpiece coming to life. However, programming is also full of woes.
How many programs - big and small, beautiful and ugly, useful and useless -
have been sucked into a tar pit?
Initially, it may not be apparent; after all, a creature can pull out one of its paws.
But what if it's all four paws are stuck?
Therefore, we should learn to avoid such tar pits.&lt;/p&gt;
&lt;p&gt;How painfully true! Even in my relatively short career (14 years and counting),
I've witnessed software systems - both small and large - struggling under the weight
of their features, unable to escape the tar pit and eventually fading away.
That's precisely why we begin with Proof of Concepts (PoCs) and
Minimal Viable Products (MVPs) and develop systems iteratively.
This is why we continuously evolve software architecture - to ensure
it remains resilient and elastic - and prevents getting into the tar pit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-mythical-man-months"&gt;
&lt;h2&gt;2 - The Mythical Man-Months&lt;/h2&gt;
&lt;p&gt;The second chapter explains why measuring a job
in &amp;quot;man-months&amp;quot; is inappropriate for software development.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Men and months are interchangeable commodities only when
a task can be partitioned among many workers with no communication
among them. This is true of reaping wheat or picking
cotton; it is not even approximately true of systems programming.&lt;/blockquote&gt;
&lt;p&gt;And yet, we continue measuring software development in &amp;quot;story points&amp;quot; - a measure
of task complexity.
We even play &amp;quot;agile poker&amp;quot; to determine a reasonable amount of story points.
Our teams digest fewer story points when someone is on vacation or sick leave,
and more story points when everyone is present. When story points seem too
abstract, we convert them into days and hours using arbitrary logarithmic scale.
For instance, 1 story point represents couple of hours of development,
while 8 story points correspond to about a week of work for a seasoned developer...
But wait a second, aren't we back to man-months again?!&lt;/p&gt;
&lt;p&gt;Are you playing agile poker? Consider using these accurate estimation cards for
the next round:&lt;/p&gt;
&lt;img alt="&amp;quot;Lunar Logic Estimation Cards&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/lunar-logic-cards.webp" style="width: 30%;" /&gt;
&lt;/div&gt;
&lt;div class="section" id="the-surgical-team"&gt;
&lt;h2&gt;3 - The Surgical Team&lt;/h2&gt;
&lt;p&gt;In the third chapter Brooks discusses team efficiency based on size and structure.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
For efficiency and conceptual integrity, one prefers a few good minds
doing design and construction. Yet for large systems one wants a way
to bring considerable manpower to bear, so that the product can make
a timely appearance.&lt;/blockquote&gt;
&lt;p&gt;How wild does a 200-man team sound?
Brooks talks of ever bigger teams - 1000 people working on OS/360.
And it's not just programmers but writers, machine operators, clerks, managers and more.
Even a brilliant, but small team is not able to tackle work that requires
the collective effort of hundreds of minds.&lt;/p&gt;
&lt;p&gt;Brooks refers to a proposal by Harlan Mills, where the chunks of work are split
between &lt;em&gt;surgical teams&lt;/em&gt;. A surgical team includes people in different
roles, much like a real surgical team that performs medical operations.
There roles include: &lt;em&gt;the surgeon, the copilot, the tester and the toolsmith, the
language expert and the editor (i.e. a technical copywriter), the administrator
and the secretaries&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Interestingly, you can easily map all these roles to the roles in modern software development teams: Product Owner (PO), team lead, engineer, tester.
While some of the roles have been automated and become unnecessary in our age,
the essence of the idea - that collaboration and specialization are crucial -
remains relevant:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
10-man team can be effective no matter how it is organized, if the
whole job is within its purview.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="aristocracy-democracy-and-system-design-1"&gt;
&lt;span id="aristocracy-democracy-and-system-design"&gt;&lt;/span&gt;&lt;h2&gt;4 - Aristocracy, Democracy and System Design&lt;/h2&gt;
&lt;p&gt;The chapter begins with a photo of the Reims
Cathedral, which unlike some of European cathedrals, exhibits sound design and
architectural integrity.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The guidebook tells, this integrity was achieved by the self-abnegation
of eight generations of builders, each of whom sacrificed
some of his ideas so that the whole might be of pure design.&lt;/blockquote&gt;
&lt;p&gt;Conceptual integrity is equally important for software systems as for buildings.
Think of Unix with its small programs that each excel at a specific task.
Can you imagine a &amp;quot;jack of all trades and the master of none&amp;quot; among them?
Probably not, because it wouldn't align with the Unix philosophy and
wouldn't be accepted by the Unix community.
Or imagine a bunch of connected  microservices,
each written in a different language, deployed across various clouds, collaborating
via non-compatible protocols. Such an architecture is a maintenance hell
destined to fail.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Conceptual integrity implies that design comes from a limited set of minds.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Brooks argues that to achieve conceptual integrity, the design of the architecture
(i.e. the interfaces of the system) must be separated from its implementation.
This doesn't mean that the architects are &amp;quot;aristocracy&amp;quot; who make all the
decisions. Rather, the architects decide &amp;quot;what should be done&amp;quot;,
while implementers decide the &amp;quot;how&amp;quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-second-system-effect"&gt;
&lt;h2&gt;5 - The second-system effect&lt;/h2&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;The second is the most dangerous system a man ever designs.
When he does his third and later ones, his prior experiences will
confirm each other as to the general characteristics of such systems,
and their differences will identify those parts of his experience
that are particular and not generalizable.&lt;/p&gt;
&lt;p&gt;The general tendency is to over-design the second system,
using all the ideas and frills that were cautiously sidetracked on
the first one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I believe that overengineering can happen at any stage of one's journey.
The fundamental concepts of our field are stable,
compared to all the hyped frameworks, tools, programming languages
and processes, that claim to solve the issues of their predecessors.&lt;/p&gt;
&lt;p&gt;In my experience, the most skilled engineers create the solutions
that are simple, elegant and efficient.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="passing-the-word"&gt;
&lt;h2&gt;6 - Passing the word&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;How can a group of 10 architects maintain the conceptual integrity
of a system which 1000 men are building?&lt;/em&gt;
This chapter is a perfect example of eternal problems on one hand and technical
progress transforming (but not completely eradicating!) the others.&lt;/p&gt;
&lt;p&gt;How did people tackle this problem on the verge of 60s and 70s? They used&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;Written specifications - the manuals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Formal definitions - API specifications.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;I think we will see future specifications to consist of both a formal definition
and a prose definition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Direct incorporation - &lt;tt class="docutils literal"&gt;#include&lt;/tt&gt; of function definitions in C,
or &lt;tt class="docutils literal"&gt;import&lt;/tt&gt; in Java to ensure correct function
signature usage in compile-time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Conferences and courts - the communities of practice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Multiple implementations - The definition will be clearer,
if there are at least two implementations in the beginning
(web standards, compilers etc.)&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;In most computer project there comes a day when it is discovered that the
machine and the manual don't agree. When the confrontation follows, the manual
usually loses, for it can be changed far more quickly and cheaply than the
machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Telephone log - Brooks advises architects to keep recordings of every
question and answer, combine and distribute those on a weekly basis - in paper format!
We have better tools (no, Confluence is not a better tool!) for this
nowadays, and a well structured and up-to-date Q&amp;amp;A log is quite handy!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Product test -
we tend to shift left in testing strategies. Software built with good test-first
practices and automated integration testing has a solid foundation, yet manual
exploratory testing can reveal so much! Independent testing is also necessary
to have get the feedback and perspective of the people who were not involved in the
development.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;The project manager's best friend is his daily adversary, the independent
product-testing organization.&lt;/p&gt;
&lt;p&gt;Every development organization needs such an independent technical auditing
group to keep it honest. In the last analysis the customer is the independent auditor.
In the merciless light of real use, every flaw will show. The product-testing
group then is the surrogate customer, specialized for finding flaws.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="why-did-the-tower-of-babel-fail"&gt;
&lt;h2&gt;7 - Why did the tower of Babel fail?&lt;/h2&gt;
&lt;p&gt;This chapter discusses communication, or rather synchronisation problems.
Brooks emphasizes the need of an up-to-date &lt;em&gt;workbook&lt;/em&gt;
- &lt;em&gt;a structure imposed on the documents that the project will be producing.&lt;/em&gt;&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
All the documents of the project need to be part of this structure.
This includes objectives, external specifications, interface specifications,
technical standards, internal specifications, and administrative memoranda.&lt;/blockquote&gt;
&lt;p&gt;Sounds like our issue trackers, rich version control systems (think Github, Gitlab etc.),
project wikis (Lord help to keep them in harmony!)&lt;/p&gt;
&lt;p&gt;How hard was it? Brooks talks of keeping a workbook on paper - which
became 5 feet (~ 1.5m!) thick and daily change distributions consisting of
150 pages! Microfische was a huge step forward which according to Brooks
saved millions of dollars on wasting paper.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
With today's system technology available, I think the technique of choice
is to keep the workbook on the direct-access file, marked with change bars
and revision dates. Each user would consult it from a display terminal.
A change summary, prepared daily, would be stored in LIFO fashion at a fixed
access point.
The programmer would probably read that daily, but if he missed a day he would
need only read longer the next day.&lt;/blockquote&gt;
&lt;p&gt;On a smaller scale - a good CHANGELOG is a crucial part of any system's API.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="calling-the-shot"&gt;
&lt;h2&gt;8 - Calling the shot&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;How long will a system programming job take? How much effort
will be required? How does one estimate?&lt;/em&gt; Half a century later, we are still bad at answering these questions.&lt;/p&gt;
&lt;p&gt;In the past, a common measure of system complexity was the number of instructions
it contained. The chapter is mostly dedicated to that topic, which is quite
outdated by today's standards.
However, we can still draw parallels, for example,the effort required
to create and maintain a system grows exponentially with its size:&lt;/p&gt;
&lt;img alt="&amp;quot;Productivity vs. Size&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/productivity-vs-size.webp" style="width: 80%;" /&gt;
&lt;p&gt;compare to the &amp;quot;Cost per line of code&amp;quot; chart from &lt;a class="reference external" href="https://zaurnasibov.com/posts/2023/05/18/clean-architecture-book-review.html"&gt;&amp;quot;Clean Architecture&amp;quot;&lt;/a&gt;:&lt;/p&gt;
&lt;img alt="&amp;quot;Cost of software per line of code&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/cost-per-loc.webp" style="width: 80%;" /&gt;
&lt;/div&gt;
&lt;div class="section" id="ten-pounds-in-a-five-pound-sack"&gt;
&lt;h2&gt;9 - Ten Pounds in a Five-Pound sack&lt;/h2&gt;
&lt;p&gt;Talks of the costs we tend to often forget.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Consider the IBM APL interactive software system. It rents for $400 per month
and, when used, takes at least 160K bytes of memory. On a Model 165,
memory rents for about $12 per kilobyte per month. If the program
is available full-time, one pays $400 software rent and $1920 memory rent for
using the program.&lt;/blockquote&gt;
&lt;p&gt;Projecting this to the present day, a &lt;tt class="docutils literal"&gt;t3.2xlarge&lt;/tt&gt; EC2 AWS instance with 32GiB
of memory costs $0.333 per hour. This is roughly $0.00000714 per KiB per month
- almost 1.7 Million times cheaper than Model 165 memory usage costs.
This insane leap took half a century, and we are not slowing down.
However, our systems have evolved as well. They grew in complexity, now serving
millions of customers concurrently,
streaming high-quality video, and processing real-time AI tasks.
Consequently, despite more affordable hardware and broader network bandwidth,
we still have to pay the price.&lt;/p&gt;
&lt;p&gt;It’s a timeless truth: we've got to keep an eye on our budgets and watch how we're
using our resources. Whether it’s CPU, memory, network bandwidth, storage,
file sizes, startup time - you name it - we need to track it all.&lt;/p&gt;
&lt;p&gt;Finally the following advice caught me off-guard, but then I recalled the
world of embedded programming, where it makes total sense:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Every project needs a notebook full of good subroutines or macros for queuing,
searching, hashing, and sorting. For each such function the notebook
should have at least two programs, the quick and the squeezed.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="the-documentary-hypothesis"&gt;
&lt;h2&gt;10 - The Documentary Hypothesis&lt;/h2&gt;
&lt;p&gt;The documentary hypothesis states that&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Amid a wash of paper, a small number of documents become the critical
pivots around which every project 's management revolves.
These are the manager's chief personal tools.&lt;/blockquote&gt;
&lt;p&gt;Brooks presents examples of documents from various projects and discusses
the necessity of formal documentation. He states that the least questions
these documents should address are:
what, when, how much, where, and who.
Take a software project, for instance:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;What: objectives and product specifications&lt;/li&gt;
&lt;li&gt;When: schedule&lt;/li&gt;
&lt;li&gt;Where: space allocation&lt;/li&gt;
&lt;li&gt;How much: budget&lt;/li&gt;
&lt;li&gt;Who: organization chart - more on this one just in few paragraphs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why have formal documents? Brooks emphasizes three matters:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Writing the decisions down is essential. It's only when we write things down,
that the gaps and inconsistencies become evident.&lt;/li&gt;
&lt;li&gt;The documents communicate the decisions to others.&lt;/li&gt;
&lt;li&gt;Manager's documents provide them with a database and a checklist.
Periodic reviews allow managers to assess their current status and determine
necessary changes in focus or direction.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Brooks mentions Conway's law when talking of organization structure that will
work on the software project.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Conway goes on to point out that the organization chart
will initially reflect the first system design, which is almost surely
not the right one. If the system design is to be free to change, the
organization must be prepared to change.&lt;/blockquote&gt;
&lt;p&gt;Indeed, &lt;a class="reference external" href="https://teamtopologies.com/book"&gt;Team Topologies&lt;/a&gt; teaches us that
we need to arrange teams according to the desired architecture and design,
not vice versa. As the design and architecture evolve, so should the
team topologies involved in product development.&lt;/p&gt;
&lt;p&gt;To some extent, everything discussed in this chapter remains relevant
to project management today.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="plan-to-throw-one-away"&gt;
&lt;h2&gt;11 - Plan To Throw One Away&lt;/h2&gt;
&lt;p&gt;So often we conflate the purpose and meaning of “Proof of Concept” with
that of a “Minimal Viable Product”.
A team working on a PoC might be forced to carry on with it to production,
rather than starting from scratch and properly building the system from the ground up,
applying the insights acquired during the PoC phase.
There is nothing new under the Sun:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The management question, therefore, is not whether to build
system and throw it away. You will do that. The only
question is whether to plan in advance to build a throwaway, or
to promise to deliver the throwaway to customers. Seen this way,
the answer is much clearer. Delivering that throwaway to customers buys time,
but it does so only at the cost of agony for the user,
distraction for the builders while they do the redesign, and a bad
reputation for the product that the best redesign will find hard to
live down.&lt;/blockquote&gt;
&lt;p&gt;There is so much wisdom in these words. A PoC is a tool to test a business hypothesis
and should be considered a throwaway. Delivering the PoC as a finished solution
to the customer always backfires: developing on a weak foundation
eventually leads to a collapse.&lt;/p&gt;
&lt;p&gt;The next topic is - &lt;strong&gt;The Only Constancy Is Change Itself&lt;/strong&gt;.&lt;/p&gt;
&lt;!-- The first step is to accept the fact of change as a way of life, rather than an
untoward and annoying exception. Cosgrove has perceptively pointed out that the
programmer delivers satisfaction of a user need rather than any tangible product.
And both the actual need and the user's perception of that need will change as
programs are built, tested, and used. --&gt;
&lt;p&gt;Both the actual need and the user’s perception of that need will evolve as
programs are developed, tested, and utilized. The &amp;quot;throw-one-away&amp;quot; concept
is essentially an acknowledgment that learning leads to changes in design.
That’s precisely why we must &lt;strong&gt;plan the system for change&lt;/strong&gt;.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The ways of designing a system for each change are well known and
widely discussed in the literature &lt;em&gt;perhaps more widely discussed than practiced.&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;Isn't it painful? We understand the need to design and implement and the system,
keeping the need for change in mind. Yet so many systems eventually collapse
under their own weight! Making changes to these systems becomes more expensive
than not touching the systems at all.&lt;/p&gt;
&lt;p&gt;Should we plan for change only in software systems? Brooks answers this
by referencing J. Cosgrove's paper &amp;quot;Needed: a new planning framework&amp;quot;,
where Cosgrove advocates for treating all plans, milestones, and schedules as
provisional to facilitate change.
Although the section is only four pages long, it contains ideas that
have been extensively discussed in &amp;quot;Accelerate&amp;quot;, &amp;quot;The DevOps Handbook&amp;quot;,
&amp;quot;Team Topologies&amp;quot; and other studies.
These include
continuous learning and experimentation across various domains, team-first thinking,
effective communication, facilitating (surgical) teams, the importance of leadership,
and more.&lt;/p&gt;
&lt;p&gt;Finally, Brooks discusses system maintenance, which he defines as
the period following a program’s installation for a customer:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The total cost of maintaining a widely used program is typically 40 percent
or more of the cost of developing it. Surprisingly, this cost is strongly
affected by the number of users. More users find more bugs.&lt;/blockquote&gt;
&lt;p&gt;Software-as-a-Service has transformed the landscape such that
software may never enter a traditional maintenance phase in its entire lifetime.
However, without a solid architecture and a team committed to continuous improvement,
an increasing amount of time will be devoted to bug fixing,
to the point where a “complete rewrite” becomes a more viable option.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Theoretically, after each fix one must run the entire bank of test cases
previously run against the system, to ensure that it has not been damaged
in an obscure way.
In practice such regression testing must indeed approximate this
theoretical ideal, and it is very costly.&lt;/blockquote&gt;
&lt;p&gt;Today, regression testing is cheap.
We have fantastic tools to fulfill the test pyramid.
Test-first development of software has become the standard.
Each modern programming language and environment comes with a handful
of unit testing frameworks and libraries.
Tools like
&lt;a class="reference external" href="https://www.docker.com"&gt;Docker&lt;/a&gt;
and
&lt;a class="reference external" href="https://testcontainers.com"&gt;Testcontainers&lt;/a&gt;
enable us to set up a &lt;em&gt;real&lt;/em&gt; database
with a &lt;em&gt;actual&lt;/em&gt; message brokers for integration testing.
Even end-to-end (E2E) tests can be automated.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sharp-tools"&gt;
&lt;h2&gt;12 - Sharp tools&lt;/h2&gt;
&lt;p&gt;From laptops, IDEs, CI services, and Source Code Management systems to phones,
circuit boards for debugging, and even the comfort of office chairs -
we rely heavily on our tools.
Nowadays, tools are generally much more affordable compared to personnel costs.
Any savings made by not acquiring the best tools often result in losses
due to slower market entry.
However, tools weren’t always so affordable, particularly in the early days of
computing.&lt;/p&gt;
&lt;p&gt;Brooks discusses the machines required by development teams,
which needed at least 1 MB of main storage and
100 MB of additional online disk storage, along with terminals.
There were other constraints as well.
Remember that machine time was a costly commodity?
This led to the scheduling of machine access among developers,
often limiting them to a few 20-minute sessions during a workday.&lt;/p&gt;
&lt;p&gt;Another common challenge was that the target computers for the final product
were not the same ones developers used to create the systems.
Either the target machines were too expensive, or they weren’t available yet.
Brooks also touches on machine simulators, performance simulators,
documentation systems, and, finally,
high-level programming languages and interactive programming!&lt;/p&gt;
&lt;p&gt;In my view, the jewel of this chapter is the discussion on the
Segregation of Duties (SoD) in the software release process.
If you ever experienced a heavy, multi-gate release processes
keep in mind that it was not invented recently!&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;When a man had his component ready for integration into a
larger piece, he passed a copy over to the manager of that larger
system, who put this copy into a system integration sublibrary. Now
the original programmer could not change it, except by permission
of the integration manager. As the system came together, the latter
would proceed with all sorts of system tests, identifying bugs and
getting fixes. From time to time a system version would be ready for wider
use.&lt;/p&gt;
&lt;p&gt;Then it would be promoted to the current version sublibrary.
This copy was sacrosanct, touched only to fix crippling bugs.
It was available for use in integration and testing of all
new module versions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="the-whole-and-the-parts"&gt;
&lt;h2&gt;13 - The Whole and The Parts&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;How does one build a program to work?
How does one test a program?
And how does one integrate a tested set of component
programs into a tested and dependable system?&lt;/em&gt;
These topics were briefly touched in the book, in this chapter
Brooks considers them more systematically.&lt;/p&gt;
&lt;p&gt;Brooks begins by emphasizing the significance of
&lt;a class="reference external" href="#aristocracy-democracy-and-system-design"&gt;Conceptual Integrity&lt;/a&gt;
in system architecture.
He then advocates for testing the &lt;em&gt;Specification&lt;/em&gt; before any implementation
starts. Consider clients testing a platform API solely based on
specification, prior to the platform's implementation being ready.
This approach can reveal numerous issues, such as
unclear or missing specification pieces,
API inconsistencies, lack of documentation etc., all of which may arise
during the implementation of client-to-platform communication.&lt;/p&gt;
&lt;p&gt;Top-Down design - a method formalized by
Niklaus Wirth in 1971 paper - in Brook's opinion,
was the most significant new programming formalization of the decade:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Briefly, Wirth's procedure is to identify design as a sequence
of refinement steps. One sketches a rough task definition and
a rough solution method that achieves the principal result.
Then one examines the definition more closely to see how the
result differs from what is wanted, and one takes the large
steps of the solution and breaks them down into smaller steps.&lt;/p&gt;
&lt;p&gt;From this process one identifies modules of solution or of data
whose further refinement can proceed independently of other
work. The degree of this modularity determines the adaptability
and changeability of the program.&lt;/p&gt;
&lt;p&gt;Wirth advocates using as high-level a notation as is possible
at each step, exposing the concepts and concealing the details
until further refinement becomes necessary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a simple and yet a very effective procedure.
We can prevent implementation details from impacting architecture,
and concentrate on the interaction between its components -
starting from the grand scale all the way down to the details.
Sounds familiar? That's right, it's Clean Architecture for you.&lt;/p&gt;
&lt;p&gt;As I write these lines, another though strikes me: design comes second.
It follows the gathering the user stories, the mapping of events, and
identification of the needs of all involved stakeholders.
Unless we get that right, the system won't address the problems of its end-users,
no matter how impeccable the design is.&lt;/p&gt;
&lt;p&gt;We've focused a lot on design, but what else does Brooks mention in this chapter?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Structured programming&lt;/em&gt;: on the verge of the 60s and 70s, programmers commonly
controlled the flow with &lt;tt class="docutils literal"&gt;GOTO&lt;/tt&gt; statements. Brooks recommends the use of
&lt;tt class="docutils literal"&gt;do/while&lt;/tt&gt; loops and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;if-then-else&lt;/span&gt;&lt;/tt&gt; statements instead.
While we have made significant progress in programming languages development,
we still employ these simple program building blocks.
Moreover, loops and conditional statements form the basis of syntactic sugar
provided by modern programming languages.&lt;/p&gt;
&lt;p&gt;The next topics are about debugging, which wasn't straightforward at all:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The programmer carefully designed his debugging procedure
planning where to stop, what memory locations to examine,
what do find there, and what to do if he didn't. This meticulous
programming of himself as a debugging machine might well take
half as long as writing the computer program to be debugged.&lt;/blockquote&gt;
&lt;p&gt;Just reading about these challenges makes you appreciate the simplicity of
setting a breakpoint and using a rich interactive debugger.&lt;/p&gt;
&lt;p&gt;At the end of the debugging section, Brooks discusses what we now refer
to as test doubles:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
One form of scaffolding is the dummy component, which consists
only of interfaces and perhaps some faked data or some small
test cases. For example, a system may include a sort program
which isn't finished yet. Its neighbors can be tested by using a
dummy program that merely reads and tests the format of input
data, and spews out a set of well-formatted meaningless but ordered
data.&lt;/blockquote&gt;
&lt;p&gt;As previously mentioned, modern programming provides fantastic tools to design
and execute tests and test doubles. Test-first development is not a luxury,
but a necessity that ensures code maintainability as it grows.&lt;/p&gt;
&lt;p&gt;Brooks concludes by addressing the control of changes, also known as
Segregation of Duties (SoD), advocating for the addition of one component
at a time and the quantization of updates.
This involves releasing in small batches and conducting
thorough regression testing.&lt;/p&gt;
&lt;p&gt;What tools assist us in these tasks nowadays? Version Control Systems,
test-first development with comprehensive unit and integration testing,
continuous integration and continuous delivery, and the strategic
launch of new features through dark launches and canary releases.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hatching-a-catastrophe"&gt;
&lt;h2&gt;14 - Hatching a catastrophe&lt;/h2&gt;
&lt;p&gt;This chapter could be perfectly illustrated by the following meme:&lt;/p&gt;
&lt;img alt="&amp;quot;Developer says that he is \&amp;quot;almost done\&amp;quot; and release will be in two days (sarcastic)&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/almost-done.webp" style="width: 60%;" /&gt;
&lt;p&gt;Well, developers are not always the guilty party, are they?&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;When one hears of disastrous schedule slippage in a project, he
imagines that a series of major calamities must have befallen it.
Usually, however, the disaster is due to termites, not tornadoes;
and the schedule has slipped imperceptibly but inexorably.&lt;/p&gt;
&lt;p&gt;Yesterday a key man was sick, and a meeting couldn't be held.
Today the machines are all down, because lightning struck the
building's power transformer. Tomorrow the disk routines won't
start testing, because the first disk is a week late from the factory.
Snow, jury duty, family problems, emergency meetings with customers,
executive audits the list goes on and on. Each one only postpones
some activity by a half-day or a day. And the schedule slips,
one day at a time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Brooks asserts that the optimal way to manage a large project is to establish
a schedule with defined milestones.
Each milestone must be concrete, specific, and measurable.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
It is more important that milestones be sharp-edged and unambiguous
than that they be easily verifiable by the boss. Rarely
will a man lie about milestone progress, if the milestone is so sharp
that he can't deceive himself.&lt;/blockquote&gt;
&lt;p&gt;This advice is universally applicable, whether in software development or room cleaning.
For instance, a ticket stating “Make the server respond faster” is inadequate.
What does “faster” mean in this context? Which responses are deemed slow?
A more precise ticket would be “Reduce the response time for Resource API
endpoints from 500ms to a maximum of 250ms.”&lt;/p&gt;
&lt;p&gt;Brooks praises PERT charts for visualizing the dependencies between activities
necessary to complete the project and identifying the critical path -
the sequence of interdependent activities that take the longest to complete.
It also indicates how much an activity can be delayed before it impacts
the critical path.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The preparation of a PERT chart is the most valuable part of
its use. Laying out the network, identifying the dependencies,
and estimating the legs all force a great deal of very specific planning
very early in a project. The first chart is always terrible, and one
invents and invents in making the second one.&lt;/blockquote&gt;
&lt;p&gt;I have no personal experience with PERT charts, so I cannot comment.
However, I’m interested in your thoughts on the matter!&lt;/p&gt;
&lt;p&gt;Finally, Brooks discusses human behavior in scenarios where a schedule begins
to fall behind. Please indulge me not making commenting on this too,
Instead, I suggest reading &lt;a class="reference external" href="https://www.triballeadership.net"&gt;&amp;quot;Tribal Leadership&amp;quot;&lt;/a&gt;
and &lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/22/turn_the_ship_around_short_review.html"&gt;&amp;quot;Turn the Ship Around!&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-other-face"&gt;
&lt;h2&gt;15 - The other face&lt;/h2&gt;
&lt;p&gt;What is the other face of a program? According to Brooks, it’s the documentation,
whether it’s for the user or a technical manual.&lt;/p&gt;
&lt;p&gt;Pause for a moment and consider the year 1970. There was no StackOverflow,
no Internet, and not even a terminal for every programmer.
Without comprehensive documentation accompanying the program,
it would be virtually useless.&lt;/p&gt;
&lt;p&gt;But even back then, Brooks advocates shipping a program with &lt;strong&gt;tests&lt;/strong&gt;!&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Every copy of a program shipped should include some small
test cases that can be routinely used to reassure the user that he
has a faithful copy, accurately loaded into the machine.&lt;/p&gt;
&lt;p&gt;Then one needs more thorough test cases, which are normally
run only after a program is modified. These fall into three parts of
the input data domain:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Mainline cases that test the program's chief functions for commonly
encountered data.&lt;/li&gt;
&lt;li&gt;Barely legitimate cases that probe the edge of the input data
domain, ensuring that largest possible values, smallest possible values,
and all kinds of valid exceptions work.&lt;/li&gt;
&lt;li&gt;Barely illegitimate cases that probe the domain boundary from
the other side, ensuring that invalid inputs raise proper diagnostic
messages.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nowadays, we seldom need to verify that a faithful copy has been accurately
loaded into the machine, but a &lt;em&gt;regression&lt;/em&gt; test suite remains absolutely
essential - both during development and upon the delivery of a program.&lt;/p&gt;
&lt;p&gt;A well-designed test suite also acts as documentation of a program’s capabilities.
A &lt;a class="reference external" href="https://zaurnasibov.com/posts/2023/02/21/specification_by_example_book_review.html"&gt;specification by example&lt;/a&gt;,
with automated tests included, precisely documents what a program does.&lt;/p&gt;
&lt;p&gt;Brooks recommends including a technical overview of the program to
facilitate easy modification. This should encompass a flow chart,
descriptions of the algorithms used,
explanations of file layouts,
and even the pass structure -
the sequence in which programs are transferred from tape or disk. Finally&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
A discussion of modifications contemplated in the original
design, the nature and location of hooks and exits, and discursive
discussion of the ideas of the original author about what
modifications might be desirable and how one might proceed.
His observations on hidden pitfalls are also useful.&lt;/blockquote&gt;
&lt;p&gt;All this reminds of &lt;a class="reference external" href="https://matklad.github.io//2021/02/06/ARCHITECTURE.md.html"&gt;ARCHITECTURE.md&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The next topic Brooks emphasizes is &lt;em&gt;Self-Documenting Programs&lt;/em&gt;.
As stated in the book, the adoption of high-level languages was not
mainstream at all. Programs were written in machine codes,
which is (sarcastically speaking) intended for machines, not for human comprehension.
However, even with machine code, it was possible to use human-friendly
symbolic names, labels, declaration statements, etc.
Comments were just as important.
Just have a look at this listing, which carries the unmistakable aroma
of the &amp;quot;old school&amp;quot; days:&lt;/p&gt;
&lt;a class="reference external image-reference" href="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/code-listing.webp"&gt;
&lt;img alt="An old code listing with thorough comments" class="align-center" src="https://zaurnasibov.com/articles/2023-12-16-mythical-man-months/code-listing.webp" style="width: 60%;" /&gt;
&lt;/a&gt;
&lt;p&gt;Brooks uses this listing as an example and explains the techniques used
to document it.&lt;/p&gt;
&lt;p&gt;Today, we still struggle with writing self-documenting code.
“Clean Code,” “Code Complete,” “The Art of Readable Code,”
“A Philosophy of Software Design” wouldn't exist if high-level languages
had solved all the problems.
Engineers still name variables &lt;tt class="docutils literal"&gt;a&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;b&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;c&lt;/tt&gt;.
Software is still written without any tests.
Specifications still come in the form of poorly-written JIRA tickets,
which look nothing like actual specifications.
Oh, I’m ranting again. :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="no-silver-bullet"&gt;
&lt;h2&gt;17 - No Silver Bullet&lt;/h2&gt;
&lt;p&gt;&amp;quot;No Silver Bullet - Essence and Accident in Software Engineering&amp;quot; (1986)
is perhaps the most renowned essay by Brooks. It was included
in the anniversary edition of the Mythical Man-Months, republished in 1995.
The paper's opening statement immediately takes you to the point:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
There is no single development, in either technology or management
technique, which by itself promises even one order-of-magnitude
improvement within a decade in productivity, in reliability, in simplicity.&lt;/blockquote&gt;
&lt;p&gt;Brooks differentiates between essential and accidental complexities in the
software development process.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Essential&lt;/em&gt; complexity comes from the abstract nature of
software's building blocks: algorithms, data sets and their relationships.
Yet, they must be highly precise and richly detailed.
There are countless ways to write a &amp;quot;Hello world&amp;quot; program.
What is to be said of anything more complicated?&lt;/p&gt;
&lt;p&gt;Brooks suggests attacking essential complexity by reducing productivity
constraints. He identifies several promising strategies: &lt;em&gt;Buy versus build&lt;/em&gt;,
&lt;em&gt;Requirements refinement and rapid prototyping&lt;/em&gt;,
&lt;em&gt;Incremental development - growing, not building, software&lt;/em&gt;, and
&lt;em&gt;Employing great designers&lt;/em&gt;.
All these ideas have stood the test of time and are parts of modern software
development.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Accidental&lt;/em&gt; complexity comes from limitations of tools, processes, hardware
and the environment. For instance, high-level languages alleviate the accidental
complexity of assembly language. Iterative software development prevents us
from committing to extensive upfront designs,
only to discover later that what we've released doesn't meet the customer needs.
Having more computing power in our pockets than we had in our desktops just
a few decades ago enables the use of more sophisticated algorithms
that now run in a reasonable time frame.&lt;/p&gt;
&lt;p&gt;Brooks evaluates technical advancements that have been praised as
potential silver bullets:
&lt;em&gt;Ada and other high-level language advances&lt;/em&gt;,
&lt;em&gt;Object-oriented programming&lt;/em&gt;,
&lt;em&gt;Expert systems&lt;/em&gt;,
&lt;em&gt;Graphical programming&lt;/em&gt;,
&lt;em&gt;Program verification&lt;/em&gt;,
&lt;em&gt;Environments and tools&lt;/em&gt;,
&lt;em&gt;Workstations&lt;/em&gt;,
finally
&lt;em&gt;AI&lt;/em&gt; and &lt;em&gt;Automatic programming&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Looking at the latter through the lens of 2024 -
Generative Pre-Trained Transformers (GPTs) and Large Language Models (LLMs)
are flourishing. We can interact with these tools in natural language and
receive code with explanations in return.
The interaction doesn't stop there; these tools can maintain context,
allowing us to refine queries for more targeted and sophisticated results.
Is this sort of &lt;em&gt;automatic programming&lt;/em&gt; a silver bullet?
In my opinion - no, at least not yet.&lt;/p&gt;
&lt;p&gt;Now, don't get
me wrong, we can throw a colossal amount of computing power to build a vast,
boundless model, capable of holding an entire Linux kernel with all its development
history in the context. But the output is still intended for human interpretation.
How much can we trust the code generated by such LLMs? How do we verify its
correctness? Would we use another LLM to generate tests, or would we craft tests
in the traditional way?
Let's get back to this discussion in five years - it's going to be interesting!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="epilogue"&gt;
&lt;h2&gt;16 - EPILOGUE&lt;/h2&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The tar pit of software engineering will continue to be sticky for
a long time to come. One can expect the human race to continue
attempting systems just within or just beyond our reach; and
software systems are perhaps the most intricate and complex of
man's handiworks. The management of this complex craft will
demand our best use of new languages and systems, our best
adaptation of proven engineering management methods, liberal
doses of common sense, and a God-given humility to recognize
our fallibility and limitations.&lt;/blockquote&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="software development"/><category term="programming"/><category term="management"/></entry><entry><title>The DevOps Handbook - review</title><link href="https://zaurnasibov.com/posts/2023/08/11/devops-handbook-review.html" rel="alternate"/><published>2023-08-11T17:40:00+03:00</published><updated>2023-08-11T17:40:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2023-08-11:/posts/2023/08/11/devops-handbook-review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2023/08/11/devops-handbook-review.html"&gt;
&lt;img alt="&amp;quot;DevOps Handbook cover&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-08-11-devops-handbook-review/devops-handbook-cover.webp" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;&lt;strong&gt;DevOps Handbook&lt;/strong&gt; is a fantastic guide for IT organizations,
that describes the ways of improving the &lt;em&gt;technology value stream&lt;/em&gt; -
the process required to convert a business hypothesis into
a technology-enabled service that delivers value to the customer.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I have started writing this review by describing the contents of each
chapter in-depth, just to realize that it's hardly possible to do that
without repeating the whole book. I usually put some conclusions at
the end of a book review, but this book is different.&lt;/p&gt;
&lt;p&gt;This is a short and emotional review of the
&lt;em&gt;DevOps Handbook: How to create world-class agility, reliability, &amp;amp; security in technology organizations&lt;/em&gt;.&lt;/p&gt;
&lt;img alt="&amp;quot;DevOps Handbook cover&amp;quot;" class="align-center" src="https://zaurnasibov.com/articles/2023-08-11-devops-handbook-review/devops-handbook-cover.webp" /&gt;
&lt;p&gt;For developers, programmers, craftsmen, and engineers,
testers and architects, operations and security overseers,
product managers, leaders, and many, many more -
to all the exceptional IT professionals out there.&lt;/p&gt;
&lt;p&gt;This is the book — the book that serves as a reminder of many things.&lt;/p&gt;
&lt;p&gt;It reminds us that programmers are not mere machines that convert assignments into code.
It underscores that QA professionals are not solely gatekeepers whose task is to extract bugs from the code programmers produce.
It highlights that Operations personnel are more than overseers of programs functioning in production.
It emphasizes that excelling as Project Managers is not about inundating products with requested features from customers.
The book unites us in our shared objectives and reminds that ultimately
&lt;em&gt;value is created only when our customers can effectively utilize our product&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This is the book - the book that imparts to us the principles of
&lt;em&gt;flow&lt;/em&gt;, &lt;em&gt;feedback&lt;/em&gt;, and &lt;em&gt;continual learning and experimentation&lt;/em&gt;
within &lt;em&gt;the technology value stream&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The First Way: The Principles of Flow&lt;/strong&gt; encompass the guidelines which help
us to accelerate the progress of code, from the moment it was committed
to the version control system, all the way until the customer is able to interact
with it in a form of a software product.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Second Way: The Principles of Feedback&lt;/strong&gt; - are the guidelines that
assist us in staying on the correct path.
Are we truly addressing customer issues?
Are we doing so efficiently?
Is security ensured?
Can we manage substantial customer loads?
Are we addressing issues as they arise?
Measure. Act. Analyze. Take action based on findings. Iterate.
Apply this approach to every process, every hypothesis, and every segment
of delivered software functionality.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Third Way: The Principles of Continual Learning and Experimentation&lt;/strong&gt;
comprise the guidelines that aid us in maintaining a cutting-edge position
and foster the creation of knowledge, both at an individual and organizational level.&lt;/p&gt;
&lt;p&gt;The book begins by building a solid foundation out of these principles.
It continues in Part II by discussing DevOps transformation, its starting points
and ways to learn and experiment without jeopardizing the rest of the organization.&lt;/p&gt;
&lt;p&gt;In Part III the author discuss
the technical practices and architecture required
to enable and sustain the fast flow of work from Development into Operations
without causing chaos and disruption to the production environment or customers.
These practices are commonly knows as &lt;em&gt;Continuous Delivery&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In Part IV the authors discuss how to implement the technical practices
of the Second Way, which are required to create fast and continuous feedback
from Operations to Development.&lt;/p&gt;
&lt;p&gt;In the last part - Part V, the book presents the practices that create
opportunities for learning, as quickly, frequently, cheaply,
and as soon as possible. This includes creating learnings from accidents and
failures, as well as
organizing and designing our systems of work so that we can constantly
experiment and learn, continually making the systems safer.&lt;/p&gt;
&lt;p&gt;Many of us have experienced some of these practices.
I was fortunate in my career to grasp and adhere to the principles
of flow and the principles of continual learning.
However, I never had the opportunity to properly experiment
or establish feedback mechanisms for such experiments,
and I am still eagerly anticipating that chance.&lt;/p&gt;
&lt;p&gt;This is &lt;strong&gt;the book&lt;/strong&gt;. Get it. Read it. Embed everything you read in your
daily work. Your colleagues, company and above of all, your customers will
be grateful.&lt;/p&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="devops"/><category term="software development"/><category term="programming"/></entry><entry><title>The curious case of denied repository access in Github Actions workflow</title><link href="https://zaurnasibov.com/posts/2023/06/01/the-curious-case-of-denied-repository-access-in-github-actions-workflow.html" rel="alternate"/><published>2023-06-01T22:59:00+03:00</published><updated>2023-06-01T22:59:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2023-06-01:/posts/2023/06/01/the-curious-case-of-denied-repository-access-in-github-actions-workflow.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2023/06/01/the-curious-case-of-denied-repository-access-in-github-actions-workflow.html"&gt;
&lt;img alt="Intro image for the article" class="align-center" src="https://zaurnasibov.com/articles/2023-06-01-the-curious-case-of-denied-repository-access-in-github-action/the-curious-case-of-denied-repository-access-in-github-action.rst.png" style="width: 100%;" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;While configuring a continuous delivery pipeline for this blog,
I encountered unexpected permission denials from GitHub.
Was there something wrong with the setup?&lt;/p&gt;
</summary><content type="html">&lt;img alt="Intro image for the article" class="align-center" src="https://zaurnasibov.com/articles/2023-06-01-the-curious-case-of-denied-repository-access-in-github-action/the-curious-case-of-denied-repository-access-in-github-action.rst.png" style="width: 100%;" /&gt;
&lt;p&gt;&lt;em&gt;GitHub Pages&lt;/em&gt; is a fantastic static site hosting service that takes HTML, CSS,
and JavaScript files straight from a repository on GitHub. It is available for
free on public repositories and allows configuring a custom domain for the site.
The site updates just in few moments after &lt;tt class="docutils literal"&gt;git push&lt;/tt&gt;.
Therefore, when it comes to choosing a platform for hosting a static blog,
opting for GitHub is an obvious choice.&lt;/p&gt;
&lt;p&gt;There are
&lt;a class="reference external" href="https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages#types-of-github-pages-sites"&gt;three types&lt;/a&gt;
of GitHub Pages sites: &lt;em&gt;project&lt;/em&gt;, &lt;em&gt;user&lt;/em&gt; and &lt;em&gt;organisation&lt;/em&gt;.
To publish a user site to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;https://&amp;lt;username&amp;gt;.github.io&lt;/span&gt;&lt;/tt&gt;, you have to create
a repository with the same name. By default, the site is served from the
master branch and the root of the repository.&lt;/p&gt;
&lt;p&gt;My blog is written in
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/ReStructuredText"&gt;reStructuredText (reST)&lt;/a&gt;
format and compiled into a static site via
&lt;a class="reference external" href="https://docs.getpelican.com/en/latest/"&gt;Pelican&lt;/a&gt;.
I keep the source of the blog in a separate private repository called (surprise!) &amp;quot;blog.&amp;quot;
The built blog site is deployed to &lt;tt class="docutils literal"&gt;basicwolf.github.io&lt;/tt&gt; via force-pushing,
so there is only a single branch with a single commit in the repository.
The whole setup allows me to hide intermediate work and expose only the end result to the public.&lt;/p&gt;
&lt;p&gt;For years I've been manually publishing the blog from my computer
- a paradoxical situation considering my longstanding advocacy
for continuous integration and delivery.
Even my other hobby projects incorporate a CI/CD pipeline in some form or another.
Finally, the time has come to set up a pipeline for the blog, and fortunately,
in the year 2023, GitHub Actions have shown to be highly effective and efficient
in getting the job done.&lt;/p&gt;
&lt;p&gt;I set up the pipeline as follows:
when a push occurs on the master branch of the &lt;tt class="docutils literal"&gt;blog&lt;/tt&gt; repository, an action is triggered.
This action builds the website, commits the resulting changes to the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;gh-pages&lt;/span&gt;&lt;/tt&gt; branch,
and pushes the branch to the &lt;tt class="docutils literal"&gt;basicwolf.github.io:master&lt;/tt&gt; repository.&lt;/p&gt;
&lt;object class="align-center" data="https://zaurnasibov.com/articles/2023-06-01-the-curious-case-of-denied-repository-access-in-github-action/publish-from-one-repo-to-another.svg" style="width: 90%;" type="image/svg+xml"&gt;Publishing from blog repository to basicwolf.github.io repository&lt;/object&gt;
&lt;p&gt;At this point, things became a little complicated. The workflow runs
within the &lt;tt class="docutils literal"&gt;blog&lt;/tt&gt; repository context but pushes the results (i.e. the site)
to the &lt;tt class="docutils literal"&gt;basicwolf.github.io&lt;/tt&gt; repository. To accomplish this I had to utilize
a dedicated personal access token (PAT) for the second repository, granting it
&lt;em&gt;Read and Write access to code&lt;/em&gt; permissions.
The token was subsequently utilized in the following manner:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
git push -f https://basicwolf:${MY_TOKEN}&amp;#64;github.com/BasicWolf/basicwolf.github.io.git gh-pages:master
&lt;/pre&gt;
&lt;p&gt;I generated a PAT and tested it by pushing the site from my computer.
Everything went smoothly, and I was looking forward to quickly complete the workflow setup.
Little did I know that I would be banging my head against the keyboard for two days,
trying to comprehend &lt;tt class="docutils literal"&gt;git push&lt;/tt&gt; permissions denials.&lt;/p&gt;
&lt;p&gt;I pushed the workflow file and began monitoring its maiden voyage.
Everything was running smoothly until the final step - pushing the site to &lt;tt class="docutils literal"&gt;basicwolf.github.io&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
git push -f ***github.com/BasicWolf/basicwolf.github.io.git gh-pages:master
remote: Permission to BasicWolf/basicwolf.github.io.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/BasicWolf/basicwolf.github.io.git/': The requested URL returned error: 403
&lt;/pre&gt;
&lt;p&gt;I won't burden you with the details of verifying that the token remained intact during the &lt;tt class="docutils literal"&gt;git push&lt;/tt&gt; process.
Whether it involved checking its length, echoing token fragments, or generating new tokens,
the token itself was sure present in the workflow.
However, despite its presence, access was denied when attempting to push from the workflow run,
while it was granted when pushing from my computer.&lt;/p&gt;
&lt;p&gt;I began suspecting that an internal authorization mechanism was to blame here.
However, the question remained: which one? Fortunately, the
&lt;a class="reference external" href="https://github.com/marketplace/actions/checkout"&gt;checkout action&lt;/a&gt;
includes comprehensive logging and provides a clue in the &amp;quot;Setting up auth&amp;quot; section:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Setting up auth
  /usr/bin/git config --local --name-only --get-regexp core\.sshCommand
  ...
  /usr/bin/git config --local http.https://github.com/.extraheader AUTHORIZATION: basic ***
&lt;/pre&gt;
&lt;p&gt;Aha! The checkout action configures authorization by setting HTTP Authorization header in  git's &lt;tt class="docutils literal"&gt;http.extraheader&lt;/tt&gt;:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;&lt;strong&gt;http.extraHeader&lt;/strong&gt;&lt;/dt&gt;
&lt;dd&gt;Pass an additional HTTP header when communicating with a server. If more than one such entry exists, all of them are added as extra headers. To allow overriding the settings inherited from the system config, an empty value will reset the extra headers to the empty list. &lt;a class="reference external" href="https://git-scm.com/docs/git-config/2.41.0#Documentation/git-config.txt-httpextraHeader"&gt;[source]&lt;/a&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;What if I read the documentation for the checkout action?&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The auth token is persisted in the local git config.
This enables your scripts to run authenticated git commands.
The token is removed during post-job cleanup .&lt;/blockquote&gt;
&lt;p&gt;The action includes a &lt;tt class="docutils literal"&gt;token&lt;/tt&gt; parameter that has a default value of &lt;tt class="docutils literal"&gt;${{ github.token }}!&lt;/tt&gt;
This token is equivalent to &lt;tt class="docutils literal"&gt;GITHUB_TOKEN&lt;/tt&gt; - a unique token generated by Github at the start of each workflow run.
However, it is important to note that this token is restricted to the repository where the workflow is executed.&lt;/p&gt;
&lt;p&gt;Finally, all the pieces of the puzzle fell into place.
What I required was a PAT with read access to the blog source repository
and write access to &lt;tt class="docutils literal"&gt;basicwolf.github.io&lt;/tt&gt;.
Once generated, I passed this PAT to the checkout action as follows:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
steps:
  - uses: actions/checkout&amp;#64;v3
    with:
      token: ${{secrets.ACCESS_TOKEN_BASICWOLF_GITHUB_IO}}
&lt;/pre&gt;
&lt;p&gt;There is no need to explicitly provide the token for git push anymore,
as the git configuration remains consistent across the steps.&lt;/p&gt;
&lt;p&gt;This marked the end of an epic quest.
The workflow pipeline successfully passed, and you have just completed reading
the first article that was automatically deployed to this blog :).&lt;/p&gt;
</content><category term="Articles"/><category term="programming"/><category term="blog"/><category term="pelican"/><category term="git"/><category term="github"/><category term="actions"/><category term="ci/cd"/><category term="access denied"/></entry><entry><title>Clean Architecture - book review</title><link href="https://zaurnasibov.com/posts/2023/05/18/clean-architecture-book-review.html" rel="alternate"/><published>2023-05-18T22:39:00+03:00</published><updated>2023-05-18T22:39:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2023-05-18:/posts/2023/05/18/clean-architecture-book-review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2023/05/18/clean-architecture-book-review.html"&gt;
&lt;img alt="&amp;quot;Clean Architecture&amp;quot; book cover" class="align-center" src="https://zaurnasibov.com/articles/2023-04-20-clean-architecture-review/clean-architecture-book-cover.jpg" style="width: 30%;" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;&lt;em&gt;Clean Architecture&lt;/em&gt; is the &amp;quot;Art of War&amp;quot; of the software industry. It was written by a professional who has been through many tough battles, both wins, and losses. Uncle Bob talks about timeless topics of software development that are just as applicable today as they were fifty years ago.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Oh, I loved the book! A warm picture emerges in my mind: late evening,
comfortable armchairs, a hot burning fire in a fireplace, and an engaging discussion
with a dear friend who happens to be one of the greatest teachers in software engineering...&lt;/p&gt;
&lt;img alt="&amp;quot;Clean Architecture&amp;quot; book cover" class="align-center" src="https://zaurnasibov.com/articles/2023-04-20-clean-architecture-review/clean-architecture-book-cover.jpg" /&gt;
&lt;p&gt;&amp;quot;Clean Architecture&amp;quot; is the &amp;quot;Art of War&amp;quot; of the software industry.
It was written by a professional who has been through many tough battles, both wins, and losses.
Uncle Bob talks about timeless topics of software development that are
just as applicable today as they were fifty years ago.&lt;/p&gt;
&lt;p&gt;Software architecture determines the necessary pieces and their integration to create the desired system.
The pieces can vary from individual variables and functions to large-scale services like databases.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The goal of software architecture is to minimize the human resources required
to build and maintain the required system.
The measure of design quality is simply the measure of the effort required to
meet the needs of the customer.&lt;/blockquote&gt;
&lt;p&gt;It is that simple! Or is it?
How many times have you struggled trying to fit a new feature into an existing code base?
How many times have you started from scratch, only to find later that the redesign became the same mess as before?&lt;/p&gt;
&lt;p&gt;Here is a scary diagram from the book.
It shows how the cost of each line of code increases with every major release.
This trend is not sustainable; no business model can make a profit while letting costs grow exponentially.&lt;/p&gt;
&lt;img alt="Market leading software product life cycle" class="align-center" src="https://zaurnasibov.com/articles/2023-04-20-clean-architecture-review/market-leading-software-product-life-cycle.png" style="width: 75%;" /&gt;
&lt;p&gt;Why does this happen? What goes wrong?
Too often, we developers buy into the familiar lie:
&lt;em&gt;&amp;quot;We can clean it up later; we just have to get to market first!&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Of course, things never do get cleaned up later, because market pressures never
abate. Getting to market first simply means that you’ve now got a horde of
competitors on your tail, and you have to stay ahead of them by running
as fast as you can.&lt;/p&gt;
&lt;p&gt;And so the developers never switch modes. They can’t go back and clean things
up because they’ve got to get the next feature done, and the next, and the next,
and the next. And so the mess builds, and productivity continues its asymptotic
approach toward zero.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Making messes is always slower than staying clean and the only way to go fast,
is to go well.&lt;/p&gt;
&lt;p&gt;We often forget that, unlike firmware, software was invented to be &amp;quot;soft.&amp;quot;
It was intended to be a way to easily change the behavior of machines.
Therefore, software architectures should be as shape-agnostic as possible.
Uncle Bob argues that for a software system to be easy to change, it is more important than for it to work.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
If you give me a program that does not work but is easy to change, then I can
make it work, and keep it working as requirements change. Therefore the
program will remain continually useful.&lt;/blockquote&gt;
&lt;p&gt;One of our responsibilities is to find the balance and
assert the importance of architecture over the urgency of features.
Sometimes we have to fight for it with the business side that is pushing to implement new features.
If architecture comes last, then the system will become even more costly to develop,
and eventually, change will become practically impossible for a part or all of the system.&lt;/p&gt;
&lt;p&gt;That is the end of &lt;strong&gt;Part I - Introduction&lt;/strong&gt;.
The rest of the tale is for you to discover, just like in 'One Thousand and One Nights'.&lt;/p&gt;
&lt;div class="section" id="inside-the-book"&gt;
&lt;h2&gt;Inside the book&lt;/h2&gt;
&lt;p&gt;In &lt;strong&gt;Part II - Starting with the Bricks: Programming Paradigms&lt;/strong&gt;, Uncle Bob discusses
structured, object-oriented, and functional programming paradigms,
and how to apply them from an architectural perspective.&lt;/p&gt;
&lt;p&gt;Each paradigm is about discipline, telling us what &lt;em&gt;not&lt;/em&gt; to do, and each paradigm
takes something away from us. Each restricts some aspect of the way we write code.&lt;/p&gt;
&lt;p&gt;In &lt;strong&gt;Part III - Design Principles&lt;/strong&gt; we learn to put the well-made software
bricks together.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Good software systems begin with clean code. On the one hand, if the bricks
aren’t well made, the architecture of the building doesn’t matter much. On the
other hand, you can make a substantial mess with well-made bricks. This is
where the SOLID principles come in.&lt;/p&gt;
&lt;p&gt;The goal of the principles is the creation of mid-level software structures that:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Tolerate change,&lt;/li&gt;
&lt;li&gt;Are easy to understand, and&lt;/li&gt;
&lt;li&gt;Are the basis of components that can be used in many software systems.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Part IV - Component Principles&lt;/strong&gt; is about arranging larger software blocks
to make a sound system.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;Components are the units of deployment. They are the smallest entities that can
be deployed as part of a system. In Java, they are jar files. In Ruby, they are gem
files. In .Net, they are DLLs. In compiled languages, they are aggregations of
binary files. In interpreted languages, they are aggregations of source files.&lt;/p&gt;
&lt;p&gt;Regardless of how they are eventually deployed, well-designed components always
retain the ability to be independently deployable and, therefore, independently
developable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We learn the principles that help in putting components together. We learn how
to group and separate the components and how to manage dependencies between them.&lt;/p&gt;
&lt;p&gt;Finally &lt;strong&gt;Part V - Architecture&lt;/strong&gt; and &lt;strong&gt;Part VI - Details&lt;/strong&gt;.
So far the book has been preparing us to grok these parts.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
The architecture of a software system is the shape given to that system by those
who build it. The form of that shape is in the division of that system into
components, the arrangement of those components, and the ways in which those
components communicate with each other.&lt;/blockquote&gt;
&lt;p&gt;Uncle Bob talks about the importance of deferring decisions about details.
Should we use a database or a plain text file? Shall we rely on TCP or UDP?
Do we use React, Vue, or Angular?
He argues that the longer we keep our options open, the more information we can gather
and the more experiments we can conduct to make an informed decision.&lt;/p&gt;
&lt;p&gt;The architecture that allows us to delay these decisions establishes clear boundaries between its components.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Software architecture is the art of drawing lines that I call boundaries.&lt;/blockquote&gt;
&lt;p&gt;This statement leads the way to &lt;strong&gt;Clean Architectures&lt;/strong&gt;, which are&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Independent of frameworks. The architecture does not depend on the existence
of some library of feature-laden software. This allows to use such
frameworks as tools, rather than forcing to cram system into their
limited constraints.&lt;/li&gt;
&lt;li&gt;Testable. The business rules can be tested without the UI, database, web server,
or any other external element.&lt;/li&gt;
&lt;li&gt;Independent of the UI. The UI can change easily, without changing the rest of
the system.&lt;/li&gt;
&lt;li&gt;Independent of the database. We can swap out Oracle or SQL Server for
Mongo, BigTable, CouchDB, or something else.&lt;/li&gt;
&lt;li&gt;Independent of any external agency. The business rules don’t know
anything at all about the interfaces to the outside world.&lt;/li&gt;
&lt;/ul&gt;
&lt;a class="reference external image-reference" href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;
&lt;img alt="Clean Architecture diagram" class="align-center" src="https://zaurnasibov.com/articles/2023-04-20-clean-architecture-review/clean-architecture.jpg" style="width: 75%;" /&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;div class="section" id="the-hidden-gem"&gt;
&lt;h2&gt;The hidden gem&lt;/h2&gt;
&lt;p&gt;Book appendices are often skipped by the readers. Don't you dare to skip this one,
because it is the hidden gem of the book. &lt;strong&gt;Architecture Archaeology&lt;/strong&gt; is
Uncle Bob's life-long software engineering journey. It is a story of creation and
discoveries, of fights and struggle of everything that lead to writing this book.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thoughts"&gt;
&lt;h2&gt;Thoughts&lt;/h2&gt;
&lt;p&gt;This is one of the &amp;quot;must-read&amp;quot; for all software engineers. The only question
is, &amp;quot;When?&amp;quot;. This book discusses many abstract topics. Unless you are intimately
familiar with software development, it may have little impact on you.
However, when you start interacting with large systems, a time comes when you sense that something is wrong, and you can't simply formalize it.
That's when you know the time has come.
The time to do architecture right.
The time to embrace Clean Architecture.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="programming"/><category term="architecture"/><category term="clean code"/><category term="clean architecture"/></entry><entry><title>Good practices: Software deployment and feature releases</title><link href="https://zaurnasibov.com/posts/2023/04/03/good-practices-software-deployment-and-feature-releases.html" rel="alternate"/><published>2023-04-03T21:52:00+03:00</published><updated>2023-04-03T21:52:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2023-04-03:/posts/2023/04/03/good-practices-software-deployment-and-feature-releases.html</id><summary type="html">&lt;p class="first last"&gt;&amp;quot;Big Bang&amp;quot; software releases are hard on end users and developers.
What can we do about it?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;em&gt;Software release&lt;/em&gt; is the process of making a new version of software available to users. Think of an application or a library uploaded to a registry, where it can be downloaded by end-users.&lt;/p&gt;
&lt;p&gt;Once software is released, it can be deployed to the target device or platform. Installing a mobile app from the App Store is a deployment. Publishing a front-end application package on a CDN is also a deployment.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;feature release&lt;/em&gt; is the process of making new functionality of software available to users.&lt;/p&gt;
&lt;div class="section" id="the-problem"&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;Companies are notorious for delivering new features through &amp;quot;Big Bang&amp;quot; releases, which often means users are not involved in the development process and do not see the new functionality until it is fully completed. This approach can result in half-baked or even unnecessary features being released.&lt;/p&gt;
&lt;p&gt;The process of Big Bang feature development is also problematic. A developer spends weeks or months working on a feature, writes the code in a separate version control branch, and does not merge it back into the mainline until it is finished. When the developer finally attempts to integrate the feature into the mainline, they often face numerous issues. Since no one else on the team is familiar with the feature's internals, the developer must be responsible for fixing all the related bugs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-good-practice"&gt;
&lt;h2&gt;A good practice&lt;/h2&gt;
&lt;p&gt;Develop the feature in short-lived version control system branches and continuously merge them into the mainline. By doing so, the feature code becomes a part of every software release. To prevent issues, guard the feature code using a feature flag and keep it in a &amp;quot;dormant&amp;quot; state.&lt;/p&gt;
&lt;p&gt;Once the feature is viable enough, it can be enabled for a small set of users who are eager to test the latest and greatest of your software, even if some functionalities are still under development. This way, you can receive feedback and iron out any issues before releasing the feature to a wider audience. Once the feature is ready, it can be delivered to all users simply by flipping the feature flag.&lt;/p&gt;
&lt;object class="align-left" data="https://zaurnasibov.com/articles/2023-04-02-good-practices-software-deployment-and-feature-releases/feature-deployments.svg" style="width: 100%;" type="image/svg+xml"&gt;Avoiding "Big Bangs" with gradual feature release.&lt;/object&gt;
&lt;p&gt;This approach helps to avoid the risks associated with a Big Bang release. By testing the code on a smaller audience beforehand, you can release with more confidence and face fewer surprises, bugs, and defects when the feature goes live.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="good practices"/><category term="software"/><category term="deployment"/><category term="release"/></entry><entry><title>Specification by example - book review</title><link href="https://zaurnasibov.com/posts/2023/02/21/specification_by_example_book_review.html" rel="alternate"/><published>2023-02-21T22:17:00+02:00</published><updated>2023-02-21T22:17:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2023-02-21:/posts/2023/02/21/specification_by_example_book_review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2023/02/21/specification_by_example_book_review.html"&gt;
&lt;img alt="&amp;quot;Specification by Example&amp;quot; by Gojko Adzic book cover." class="align-center" src="https://zaurnasibov.com/articles/2023_02_21_specification_by_example/specification_by_example_book_cover.jpg" /&gt;
&lt;/a&gt;
&lt;p&gt;Doing things right doesn't matter unless you do the right thing.
&amp;quot;Specification by Example&amp;quot; by Gojko Adzic is about delivering the right
software. Adzic has interviewed many successful teams and discovered
that their ways of software development are quite similar.
These ways or processes are based on a close collaboration between
all the parties, including business representatives.
It begins by understanding the business goals.
It continues with creating a specification and utilizing it for
software development and verification.
It is finalized by providing living documentation which reflects
the current software state and behaviour.&lt;/p&gt;
&lt;p class="last"&gt;&amp;quot;Specification by Example&amp;quot; helped me to understand how to do
behaviour-driven development (BDD).
It is an excellent reading for a software craftsman.&lt;/p&gt;
</summary><content type="html">&lt;img alt="&amp;quot;Specification by Example&amp;quot; by Gojko Adzic book cover." class="align-center" src="https://zaurnasibov.com/articles/2023_02_21_specification_by_example/specification_by_example_book_cover.jpg" /&gt;
&lt;p&gt;Merriam-Webster dictionary
&lt;a class="reference external" href="https://www.merriam-webster.com/dictionary/specification"&gt;defines&lt;/a&gt;
&lt;em&gt;specification&lt;/em&gt; as&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;The act of specifying - naming or stating explicitly or in detail.&lt;/li&gt;
&lt;li&gt;A detailed, precise presentation of something or a plan or proposal
for something.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think of specification as
&lt;em&gt;a definition of what the system is expected to do&lt;/em&gt;.
Ah, if only systems always behaved as they were supposed to!&lt;/p&gt;
&lt;p&gt;You darn well know, how that happens.
First comes the business, with brilliant or not-so ideas.
&amp;quot;We are going to make a new product! It will increase our revenue! ...
[an hour later] and the button text should be in red!&amp;quot;.
The Business Analysts mince that into a Business case™.
The POs scrutinize the case into user stories.
The QA write acceptance criteria.
Finally, the developers start implementing.
But the business has already given the teams a detailed
vision of how things should be, so there is not much thinking on the way,
just turning JIRA tickets into code. There is even no need to roll it out
in small chunks to the end customer - the business already knows what the
customer wants...
This half a century old illustration has not aged by a single second:&lt;/p&gt;
&lt;img alt="The Swing - from the University of London Computer Centre Newsletter No. 53, March 1973" class="align-center" src="https://zaurnasibov.com/articles/2023_02_21_specification_by_example/computer_centre_treeswing_pictures.jpg" /&gt;
&lt;p&gt;Gojko Adzic analyzed the software industry fallacies that lead to such a result.
He found out that &lt;em&gt;how&lt;/em&gt; companies deal with these fallacies is very
much alike. The methods and processes are shared by the most successful teams that he interviewed
while researching for the book.
He talks of these methods as &lt;em&gt;a set of process patterns that facilitate change in software
products to ensure the right product is delivered effectively.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The foundation of every key pattern is &lt;strong&gt;collaboration&lt;/strong&gt;.
Gojko noticed that the &amp;quot;handover&amp;quot; journey of specifications through business people,
product managers, developers, and QA is full of misunderstanding, ambiguity, information losses,
errors and unnecessary work.
&amp;quot;&lt;em&gt;Specification by example&lt;/em&gt;&amp;quot; teaches how to build a shared understanding between
everyone involved in the software creation process.
It then demonstrates how to translate the shared understanding into specification
documents, leverage them for continual system testing, and produce up-to-date
documentation that evolves with the system.&lt;/p&gt;
&lt;div class="section" id="key-process-patterns-in-a-tiny-nutshell"&gt;
&lt;h2&gt;Key process patterns in a tiny nutshell&lt;/h2&gt;
&lt;p&gt;A successful team begins by &lt;em&gt;deriving scope from a customer's business goals&lt;/em&gt;.
They collaborate to define the scope that will achieve the goal.
The business representatives explain the intent and the value of the feature,
so that everyone understands what's needed. Then, the team works with the business
to determine the solution.&lt;/p&gt;
&lt;p&gt;The teams collaborate and specify the solution together with the business people.
&lt;em&gt;Specifying collaboratively&lt;/em&gt; allows to utilize the expertise of stakeholders,
gather different ideas about the solution and make everyone more engaged.&lt;/p&gt;
&lt;p&gt;The stakeholders tightly work together to &lt;em&gt;illustrate specifications using examples&lt;/em&gt;.
They identify the &lt;em&gt;key examples&lt;/em&gt; which unambiguously define &lt;em&gt;what&lt;/em&gt; the software needs to do.
They’re both the target for development and serve an evaluation criterion
to see whether the development is done.&lt;/p&gt;
&lt;img alt="Key process patterns" class="align-center" src="https://zaurnasibov.com/articles/2023_02_21_specification_by_example/key_process_patterns.png" /&gt;
&lt;p&gt;Key examples are a great starting point for creating specification, but
they are not specification yet. Gojko emphasizes, that the common reason
for teams to fail with Specification by Example - is not taking the time to
process the raw key examples.
Successful teams don’t use raw examples; they &lt;em&gt;refine the specification&lt;/em&gt; from them.
The teams carve out the essence of a key example, discard the unnecessary
details and turn it into a clear definition of the desired system behaviour.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;Ideally, a specification with examples should unambiguously define the
required functionality from a business perspective
&lt;em&gt;but not how the system is supposed to implement it&lt;/em&gt;.&lt;/p&gt;
&lt;p class="last"&gt;&lt;strong&gt;A good specification, with examples, is effectively an acceptance test for
the described functionality.&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Automating the validation process&lt;/em&gt; is a proven way to avoid the bottlenecks of
manual testing.
What's important is that the teams validate &lt;em&gt;without changing specifications&lt;/em&gt;.
Otherwise, all the value of refining specifications is lost.
Such automated, comprehensible and accessible to all the team members
specification with examples becomes an &lt;em&gt;executable specification&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When the validation process happens frequently, the stakeholders are sure
that the software works according to the specification.
However, how and in which form can they access the verification results?
Hence the team continues sharpening the executable specifications and organises
the verification output to provide all stakeholders a consistent,
easy-to-understand and up-to-date &lt;em&gt;living documentation&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thoughts"&gt;
&lt;h2&gt;Thoughts&lt;/h2&gt;
&lt;p&gt;Specification by Example is Behaviour-Driven Development. Gojko Adzic
avoided the term since it was too ambiguous, and the meaning was changing all the time.
It's been almost fifteen years since the book was written,
and BDD is still ambiguous and misunderstood by large and small companies alike.&lt;/p&gt;
&lt;p&gt;In one company, the team was participating in meetings with the clients, and
together they derived scope from the business goals. They even documented
the key examples that the customer provided. But it never went further - the
specifications were extracted to JIRA tickets hierarchy and remained there
never to be seen again, once the tickets got closed.&lt;/p&gt;
&lt;p&gt;In another company, the user stories were extracted into Cucumber-based behaviour tests.
But these tests got written AFTER the implementation in code!
They have reflected how developers implemented the software, not how it was supposed
to behave.&lt;/p&gt;
&lt;p&gt;The third company used Cucumber for contract testing of HTTP API.
That nicely fits into &amp;quot;101 ways of abusing Given, When, Then&amp;quot;.&lt;/p&gt;
&lt;p&gt;Least to say, that none of these companies had living documentation.&lt;/p&gt;
&lt;p&gt;&amp;quot;Specification by Example&amp;quot; tells the story of teams and companies that
succeeded in BDD.
Gojko first talks about the obstacles that the teams should go through
to change the mindset about BDD. He continues with a detailed explanation of
every key pattern - every pattern has a designated chapter.
The last six chapters of the book are the case studies, which narrate the companies
journey from  waterfall and &amp;quot;agile-ish&amp;quot; development processes to specification by example.&lt;/p&gt;
&lt;p&gt;To my shame, I have yet to build a system that incorporates all the key patterns
described in the book. And I am eagerly looking forward to it!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="related"&gt;
&lt;h2&gt;Related&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2024/09/29/testified-documentation.html"&gt;Testified Documentation (2024)&lt;/a&gt;
- my idea of maintaining documentation by live-testifying it with tests results.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="programming"/><category term="specification"/><category term="requirements"/><category term="BDD"/><category term="collaboration"/></entry><entry><title>Hexagonal architecture and Python - Part III: Persistence, Transactions, Exceptions and The Final Assembly</title><link href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html" rel="alternate"/><published>2022-12-31T17:19:00+02:00</published><updated>2022-12-31T17:19:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2022-12-31:/posts/2022/12/31/hexarch_di_python_part_3.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html"&gt;
&lt;img alt="Python logo in a hexagon with Roman III literal" class="align-center" src="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/hexagonal-python-3.jpg" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Welcome to the third part of the article series, which cover principles of
Hexagonal architecture, Dependency Injection, Domain-Driven Design and applies
these all to Python and Django application design.&lt;/p&gt;
</summary><content type="html">&lt;a class="reference external image-reference" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html" id="hexarch-di-python-part-3"&gt;
&lt;img alt="Python logo in a hexagon with Roman III literal" class="align-center" src="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/hexagonal-python-3.jpg" /&gt;
&lt;/a&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;Part I: Dependency Injection and componential architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II: Domain,  Application Services, Ports and Adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html"&gt;Part III: Persistence, Transactions, Exceptions and The Final Assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html"&gt;Part IV: Lightweight integration tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/tree/blog3"&gt;The code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In
&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II&lt;/a&gt;
we discussed the Hexagonal architecture of ports and adapters,
the role of the Domain layer and its influence on API and database layers.
We exposed the application to the outer world via the HTTP API port.&lt;/p&gt;
&lt;p&gt;In Part III we are going to
put all the application pieces together.
But before that,
we have to connect the application to the database,
research Django transactions in unit tests and
set up exception handling on the HTTP API level.&lt;/p&gt;
&lt;div class="section" id="the-repository"&gt;
&lt;h2&gt;The repository&lt;/h2&gt;
&lt;p&gt;We love Django for many things, but most of them all - is the fantastic ORM.
Django ORM abstracts the underlying database so gracefully that
swapping one database engine to another is just a matter of updating the application
configuration.
But what if there is another data storage not supported by Django?
What if the data storage is a web service?&lt;/p&gt;
&lt;p&gt;This problem is commonly solved via the
&lt;a class="reference external" href="https://learn.microsoft.com/en-us/previous-versions/msp-n-p/ff649690(v=pandp.10)"&gt;Repository design pattern&lt;/a&gt;.
A repository separates the logic of communicating with the database
from the rest of the application. In terms of Hexagonal architecture, a
repository is an SPI adapter that handles commands and queries from one
or more related ports.&lt;/p&gt;
&lt;p&gt;Code-wise, the &lt;tt class="docutils literal"&gt;VotingUserRepository&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py#L21"&gt;[source]&lt;/a&gt;
is a class that implements
the &lt;tt class="docutils literal"&gt;FindVotingUserPort&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/port/spi/find_voting_user_port.py#L8"&gt;[source]&lt;/a&gt;
and the &lt;tt class="docutils literal"&gt;SaveVotingUserPort&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/port/spi/save_voting_user_port.py#L6"&gt;[source]&lt;/a&gt;
ports:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUserRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;FindVotingUserPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;SaveVotingUserPort&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find_voting_user&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;article_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;save_voting_user&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;voting_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Strictly speaking, there is no need to use the Repository pattern here.
We have already decoupled the application from the data stores via SPI ports.
However, a repository is a convenient way of putting related adapter implementations
in one place.
The &lt;tt class="docutils literal"&gt;VotingUserRepository&lt;/tt&gt; provides database-backed adapters for both
&lt;tt class="docutils literal"&gt;FindVotingUserPort&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;SaveVotingUserPort&lt;/tt&gt; SPI ports.
It communicates with the database through Django ORM:&lt;/p&gt;
&lt;object class="align-center" data="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/the-voting-user-repository.svg" style="width: 100%;" type="image/svg+xml"&gt;A diagram which shows the data flow between VotingUserRepository,
Django ORM and a Database.&lt;/object&gt;
&lt;div class="section" id="from-domain-models-to-database-entities"&gt;
&lt;h3&gt;From domain models to database entities&lt;/h3&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;VotingUserRepository&lt;/tt&gt; has to map the &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; domain model to
data model(s) when saving to - and vice versa, when reading from the database.
The &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; model holds three pieces of information,
which eventually influence the database design
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/domain/model/voting_user.py#L20"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/domain/model/voting_user.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;
    &lt;span class="n"&gt;karma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Karma&lt;/span&gt;
    &lt;span class="n"&gt;votes_for_articles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ArticleVote&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;A modern relational database with native JSON support can store such
an object in a single table row. Django natively supports JSON fields
and provides unbelievable
&lt;a class="reference external" href="https://docs.djangoproject.com/en/4.1/topics/db/queries/#querying-jsonfield"&gt;JSON querying capabilities&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A more traditional way is to store &lt;tt class="docutils literal"&gt;ArticleVotes&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;VotingUsers&lt;/tt&gt; in separate
tables with an explicit relationship between them:&lt;/p&gt;
&lt;img alt="uml diagram" class="align-center" src="https://zaurnasibov.com/images/d662121a.png" /&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Although I drew &lt;tt class="docutils literal"&gt;article_vote.user_id&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;article_vote.article_id&lt;/tt&gt; as
&lt;strong&gt;foreign keys&lt;/strong&gt;, this is not reflected in the example project code.
There is some hidden complexity here, like -
if a user gets deleted, should the article votes stay? Or should they remain
intact if an article gets deleted? If yes - how should we preserve the data?
I hope you would indulge me this simplification and leave the
proper foreign key relationships and domain-specific deletion handling for
another time.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I bet you already picture how to express these tables as Django models.
Here is a tricky question: where should we put them?
It's not hard to answer if you remember the structure of HTTP API adapters.
Let's do something similar for our persistence SPI adapter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;myapp/application/adapter/spi/
    persistence/
        entity/
            article_vote_entity.py     # Django model here
            voting_user_entity.py      # and here
        repository/
            voting_user_repository.py
        exceptions/
            ...
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here is another unorthodox move: I called Django models &amp;quot;&lt;em&gt;Entities&lt;/em&gt;&amp;quot;.
That is - to avoid confusion between &lt;em&gt;domain models&lt;/em&gt; and &lt;em&gt;Django models&lt;/em&gt;.
There is no other hidden meaning of &amp;quot;Entity&amp;quot; in this case.&lt;/p&gt;
&lt;p&gt;Here is the &lt;tt class="docutils literal"&gt;ArticleVoteEntity&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/entity/article_vote_entity.py#L8"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/entity/article_vote_entity.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleVoteEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;VOTE_UP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;up&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;VOTE_DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;

    &lt;span class="n"&gt;VOTES_CHOICES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VOTE_UP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;UP&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VOTE_DOWN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;DOWN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUIDField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;editable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUIDField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;article_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUIDField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;vote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;VOTES_CHOICES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;unique_together&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;article_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;db_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;article_vote&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;VotingUserEntity&lt;/tt&gt; is simpler
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/entity/voting_user_entity.py"&gt;[source]&lt;/a&gt;
:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/entity/voting_user_entity.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UUIDField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;editable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;karma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;db_table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;voting_user&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The entity definitions are lean and have no methods in them.
All that is required - is to map data from Python to database and back.
And Django flawlessly does that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="inside-the-repository"&gt;
&lt;h3&gt;Inside the repository&lt;/h3&gt;
&lt;p&gt;Once you've seen the entities (i.e. Django models), things get very predictable.
The repository implements two SPI ports - one to get a &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; from the
database, another to persist a &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; to the database.
The repository takes care of transforming the domain model to Django entities
and calling the required Django ORM methods. The repository then transforms
the result back to the domain model:&lt;/p&gt;
&lt;object class="align-center" data="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/voting-user-to-database.svg" style="width: 100%;" type="image/svg+xml"&gt;A diagram which shows how VotingUser domain model is persisted to
a database through Django ORM mechanism.&lt;/object&gt;
&lt;p&gt;The implementation fits just in few lines after hiding Django ORM boilerplate in
private methods
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py#L25"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find_voting_user&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;article_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;voting_user_entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_voting_user_entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;votes_for_articles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_votes_for_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&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;VotingUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Karma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voting_user_entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;karma&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;votes_for_articles&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Remember that I put no explicit &lt;tt class="docutils literal"&gt;ForeignKey&lt;/tt&gt; relationships here, so we
have to load the votes manually. A user is saved in the same fashion
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py#L57"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;save_voting_user&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;voting_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;saved_voting_user_entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_voting_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voting_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;saved_article_vote_entities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_votes_for_articles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;voting_user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;votes_for_articles&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_voting_user_entity_to_domain_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;saved_voting_user_entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;saved_article_vote_entities&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Perhaps you are wondering: &lt;strong&gt;why map a&lt;/strong&gt; &lt;tt class="docutils literal"&gt;VotingUserEntity&lt;/tt&gt; &lt;strong&gt;back to a&lt;/strong&gt;
&lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; &lt;strong&gt;domain model if we already pass it as an argument?&lt;/strong&gt;
The data passed in an INSERT INTO statement may run through numerous
transformations before it reaches the data storage.
The well-known case is an &amp;quot;auto-incremental&amp;quot; integer primary key
generated via &lt;tt class="docutils literal"&gt;BEFORE INSERT&lt;/tt&gt; triggers.
So, it is paramount to return a domain model that resembles
the updated database state, not what we pass to the routine.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="transactions-management"&gt;
&lt;h2&gt;Transactions management&lt;/h2&gt;
&lt;p&gt;A common way to handle database transactions in Django - is to wrap each HTTP
request in a transaction.
This works for simple cases. But what does it mean in terms of
Hexagonal architecture? In
&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II&lt;/a&gt;
we created an HTTP API adapter, which invokes the &lt;tt class="docutils literal"&gt;VoteForArticleUseCase&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/port/api/vote_for_article_use_case.py#L9"&gt;[source]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But there could be many other adapters - a command line adapter,
a message bus adapter, an RPC adapter etc.
We can't trust all those adapters to wrap a use case in a transaction.
So, the burden of defining transaction boundaries is shifted to
a use case implementation - an application service.
An application service places the database write operations into a single transaction.
The operations then roll back if one of them fails.&lt;/p&gt;
&lt;div class="section" id="transactions-in-django"&gt;
&lt;h3&gt;Transactions in Django&lt;/h3&gt;
&lt;p&gt;We know that an application service
vows to be agnostic of SPI adapters' implementation details.
But wrapping SPI calls in transaction breaks this vow.
Correction: wrapping SPI calls in a transaction &lt;em&gt;using Django routines&lt;/em&gt; breaks
this vow.
Django's &lt;a class="reference external" href="https://docs.djangoproject.com/en/4.1/topics/db/transactions/#controlling-transactions-explicitly"&gt;transaction.atomic&lt;/a&gt;
is the unambiguous way to wrap a code block in a transaction.
It is used either as a decorator or a context manager.
But the problem is that Python decorators and context managers are runtime
constructs. Internally &lt;tt class="docutils literal"&gt;transaction.atomic&lt;/tt&gt; operates on database connection
object. While we certainly need a database connection at a run time, we
don't need one for &lt;em&gt;unit&lt;/em&gt; testing.
This means that the following perfectly valid production code&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;django.db&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;atomic&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;fails in a unit test (pytest) with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;RuntimeError(&amp;quot;Database&lt;/span&gt; access not &lt;span class="pre"&gt;allowed...&amp;quot;)&lt;/span&gt;&lt;/tt&gt; exception, unless a database connection is established.
The exception suggest marking the test with &lt;strong&gt;&amp;#64;pytest.mark.django_db&lt;/strong&gt; - but
this turns a &lt;em&gt;unit&lt;/em&gt; test into an &lt;em&gt;integration&lt;/em&gt; test!&lt;/p&gt;
&lt;p&gt;With all the &amp;quot;batteries included&amp;quot;, Django doesn't include one for this case.
My version of such a battery is &lt;tt class="docutils literal"&gt;&amp;#64;transactional&lt;/tt&gt; decorator, which
wraps a callable in a transaction for production, but skips it when running tests
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/util/transactional.py#L11"&gt;[source]&lt;/a&gt;.&lt;/p&gt;
&lt;div class="admonition warning"&gt;
&lt;p class="first admonition-title"&gt;Warning&lt;/p&gt;
&lt;p class="last"&gt;&lt;strong&gt;Code smell detected&lt;/strong&gt;.
A routine in a production code made solely for the sake of testing is
a sign of a bad design. However, such hack is necessary to push a Django
application out of the framework box.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="spi-adapters-exceptions"&gt;
&lt;h2&gt;SPI adapters exceptions&lt;/h2&gt;
&lt;p&gt;Traditionally handling exceptions in Django views boils down to wrapping a block of
code in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;try..except&lt;/span&gt;&lt;/tt&gt; and returning an error-indicating result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_user_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&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;HttpResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&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;HttpResponseNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;User not found :(&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But how does an API adapter handles an exception raised by an SPI adapter?
The dependencies directions principle in Hexagonal Architecture reminds us that
API adapters should not be aware of SPI &lt;strong&gt;adapters&lt;/strong&gt;' innards.&lt;/p&gt;
&lt;object class="align-center" data="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/hexagonal-architecture-dependencies.svg" style="width: 35%;" type="image/svg+xml"&gt;Hexagonal Architecture layers, from top to bottom: Adapters, Ports,
Application Services, Domain&lt;/object&gt;
&lt;p&gt;Instead, they are aware of interfaces exposed by SPI &lt;strong&gt;ports&lt;/strong&gt;.
An SPI &lt;strong&gt;port&lt;/strong&gt; is not necessarily a bare interface.
It includes type definitions, exceptions and other constructs that make an SPI
port a whole. Our SPI port includes such an exception
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/exceptions/voting_user_not_found.py"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/exceptions/voting_user_not_found.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUserNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;User &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39; not found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The SPI adapter catches the downstream &lt;tt class="docutils literal"&gt;User.DoesNotExist&lt;/tt&gt; exception
and re-throws it upstream in form of &lt;tt class="docutils literal"&gt;VotingUserNotfound&lt;/tt&gt;
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py#L39"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/spi/persistence/repository/voting_user_repository.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_get_voting_user_entity&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;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&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;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DoesNotExist&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;VotingUserNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;e&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="section" id="exception-handler"&gt;
&lt;h3&gt;Exception handler&lt;/h3&gt;
&lt;p&gt;Now that we know which exception to catch in the HTTP API adapter,
let's discuss ways to handle it.
The most obvious way is to wrap the body of &lt;tt class="docutils literal"&gt;ArticleVoteView.post()&lt;/tt&gt; in
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;try..except&lt;/span&gt;&lt;/tt&gt; statement.
That works fine for a small number of exceptions, but in a larger
application with lots of exceptions of a similar origin, a common mechanism might
be preferable.
For example, an &amp;quot;Entity Not Found&amp;quot; exception can be expressed as the &lt;tt class="docutils literal"&gt;HTTP 404&lt;/tt&gt;
response for any kind of entity.
Luckily for us, Django Rest Framework provides a common exception-handling mechanism.
You can define a
&lt;a class="reference external" href="https://www.django-rest-framework.org/api-guide/exceptions/#custom-exception-handling"&gt;custom exception handler&lt;/a&gt;
function and set &lt;tt class="docutils literal"&gt;REST_FRAMEWORK.EXCEPTION_HANDLER&lt;/tt&gt; settings value.&lt;/p&gt;
&lt;p&gt;If a simple form, the handler catches SPI exceptions and converts them to an HTTP
response
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/application/adapter/api/http/exceptions_handler.py"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/api/http/exceptions_handler.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;exceptions_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VotingUserNotFound&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;Response&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Error&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;detail&amp;#39;&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;exc&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BAD_REQUEST&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="the-final-assembly"&gt;
&lt;h2&gt;The Final Assembly&lt;/h2&gt;
&lt;p&gt;All the components of the application - the domain model, application services,
API and SPI adapters are ready. All that is left - is to put them together.
We are going to use a small dependencies or
&lt;a class="reference external" href="https://www.martinfowler.com/articles/injection.html"&gt;Inversion of Control&lt;/a&gt;
container that creates all the components instances and wires them into a
complete application:&lt;/p&gt;
&lt;object class="align-center" data="https://zaurnasibov.com/articles/2022_12_31_hexarch_di_python_part_3/ioc-container.svg" style="width: 80%;" type="image/svg+xml"&gt;A diagram which shows how Django passes control flow to the IoC
Container.&lt;/object&gt;
&lt;p&gt;The container commences by instantiating &lt;tt class="docutils literal"&gt;VotingUserRepository&lt;/tt&gt;.
It is the sole component with no dependencies.
Next, the container instantiates the components that depend
on the already available components instances, i.e. &lt;tt class="docutils literal"&gt;ArticleRatingservice&lt;/tt&gt;
that solely depends upon &lt;tt class="docutils literal"&gt;VotingUserRepository&lt;/tt&gt;.
It continues recursively assembling components until the dependency tree is
fully populated
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/dependencies_container.py#L10"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/dependencies_container.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;build_production_dependencies_container&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Dict&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;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;voting_user_repository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VotingUserRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;article_rating_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;find_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;voting_user_repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;save_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;voting_user_repository&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;article_vote_django_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArticleVoteView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;vote_for_article_use_case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;article_rating_service&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;article_vote_django_view&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;article_vote_django_view&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Notice that container only exposes a single entry point: the HTTP view, i.e.
the API adapter.&lt;/p&gt;
&lt;div class="section" id="configuration"&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;Where and when should we build the container? Consider this: the container
creates and wires the components together. We can use different components
for different environments - e.g. have a &lt;tt class="docutils literal"&gt;VotingUserExcelRepository&lt;/tt&gt;.
So, the container &lt;strong&gt;configures&lt;/strong&gt; the application.
And Django applications have a well-known place for configurations - the
&lt;a class="reference external" href="https://docs.djangoproject.com/en/dev/ref/applications/#django.apps.AppConfig"&gt;AppConfig&lt;/a&gt; class
and the &lt;tt class="docutils literal"&gt;AppConfig.ready()&lt;/tt&gt; method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/apps.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyAppConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;myapp&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&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;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ready&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;myapp.dependencies_container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;build_production_dependencies_container&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_production_dependencies_container&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="urls"&gt;
&lt;h3&gt;URLs&lt;/h3&gt;
&lt;p&gt;The application configuration registry is populated &lt;em&gt;before&lt;/em&gt; Django sets up
the URLs. It allows to get the application configuration from the registry
and bind the view to a URL
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/urls.py"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/urls.py&lt;/span&gt;

&lt;span class="n"&gt;app_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;django_apps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_containing_app_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myapp&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;article_vote_django_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;container&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;article_vote_django_view&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;urlpatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;article_vote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_vote_django_view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="django-models"&gt;
&lt;h3&gt;Django models&lt;/h3&gt;
&lt;p&gt;Django expects to find models in application's &lt;tt class="docutils literal"&gt;models.py&lt;/tt&gt; file.
Since we declared the entities deep down in SPI adapters, they have to be
imported manually here
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/src/myapp/models.py"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/models.py&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;myapp.application.adapter.spi.persistence.entity.article_vote_entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ArticleVoteEntity&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;myapp.application.adapter.spi.persistence.entity.voting_user_entity&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;VotingUserEntity&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="testing"&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The Final Assembly&lt;/strong&gt; is a slightly misleading term. There is no need to wait
for all the components to be available to assemble a production-level
application container.
On the surface, a container exposes an API entry point,
backed either by a production-grade component or a dummy.&lt;/p&gt;
&lt;p&gt;So, the dependencies container should not be the last but one of the
first items on the list when building an application following
Hexagonal architecture principles.
You can add the components to the container as they get ready and test every time
how they fit together
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog3/tests/test_myapp/test_dependencies_container.py"&gt;[source]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# tests/test_myapp/test_dependencies_container.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_build_production_ioc_container&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;build_production_dependencies_container&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;At the same time, a simple &lt;strong&gt;smoke test&lt;/strong&gt; can make a vote by a non-existing
user and expect a response with HTTP 404 - Not Found status back:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;http://localhost:8000/api/article_vote&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
--header&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Type: application/json&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
--request&lt;span class="w"&gt; &lt;/span&gt;POST&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
--data&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&lt;/span&gt;
&lt;span class="s1"&gt;   &amp;quot;user_id&amp;quot;: &amp;quot;efed6f83-49ee-4cbc-bdbd-2b92bf428f2b&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;   &amp;quot;article_id&amp;quot;: &amp;quot;60ccea0c-0bf2-4726-8ac7-324fa03a74cd&amp;quot;,&lt;/span&gt;
&lt;span class="s1"&gt;   &amp;quot;vote&amp;quot;: &amp;quot;UP&amp;quot;&lt;/span&gt;
&lt;span class="s1"&gt; }&amp;#39;&lt;/span&gt;

&amp;gt;
&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;title&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;Error&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;detail&amp;quot;&lt;/span&gt;:&lt;span class="s2"&gt;&amp;quot;User &amp;#39;efed6f83-49ee-4cbc-bdbd-2b92bf428f2b&amp;#39; not found&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;status&amp;quot;&lt;/span&gt;:404
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Bear in mind that the job of a smoke test is to verify whether the application
works. An ideal smoke test touches all the application layers
without affecting its state. Voting by a non-existing user cuts through all the
application layers, down to the database and returns the expected error result.&lt;/p&gt;
&lt;p&gt;This test can also run against an application-in-development with
a dummy HTTP or SPI (database) adapters.
Replacing a dummy adapter with a real one should not require any
modifications to the test.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="final-thoughts"&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;It took me almost two years to complete this article series. The example code
lived through two major rewrites and has been continuously evolving.
I am satisfied with the output and the outcome of this work.
It helped me to understand Hexagonal Architecture and dive deeper into DDD.
I hope it makes an inspiring impact on fellow Pythonistas!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h2&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;Traditionally, &lt;a class="reference external" href="https://jereteittinen.info"&gt;Jere &amp;quot;Urokhtor&amp;quot; Teittinen&lt;/a&gt;
gave priceless feedback on the draft, for which I am very grateful!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="architecture"/><category term="DDD"/><category term="dependency injection"/><category term="Django"/><category term="hexagonal architecture"/><category term="programming"/><category term="python"/></entry><entry><title>Refactoring - book review</title><link href="https://zaurnasibov.com/posts/2022/10/15/refactoring_book_review.html" rel="alternate"/><published>2022-10-15T12:00:00+03:00</published><updated>2022-10-15T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2022-10-15:/posts/2022/10/15/refactoring_book_review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2022/10/15/refactoring_book_review.html"&gt;
&lt;img alt="&amp;quot;Refactoring&amp;quot; book front cover" class="align-center" src="https://zaurnasibov.com/articles/2022_10_15_refactoring_book_review/refactoring_book_cover.webp" /&gt;
&lt;/a&gt;
&lt;p&gt;&lt;em&gt;Refactoring&lt;/em&gt; is a book by Martin Fowler
about what a fellow developer  might describe as
&amp;quot;a process of improving the code quality.&amp;quot;&lt;/p&gt;
&lt;p class="last"&gt;I highly recommend this book to software professionals who want to improve and formalise their refactoring skills.&lt;/p&gt;
</summary><content type="html">&lt;img alt="&amp;quot;Refactoring&amp;quot; book front cover" class="align-center" src="https://zaurnasibov.com/articles/2022_10_15_refactoring_book_review/refactoring_book_cover.webp" /&gt;
&lt;p&gt;&lt;em&gt;Refactoring&lt;/em&gt; is a book by Martin Fowler (with contributions by Kent Beck)
about what a fellow developer  might describe as
&amp;quot;a process of improving the code quality.&amp;quot;&lt;/p&gt;
&lt;p&gt;Martin Fowler defines its meaning  more accurately:&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Refactoring&lt;/strong&gt; (&lt;em&gt;noun&lt;/em&gt;) -
A change made to the internal structure of software to make it easier
to understand and cheaper to modify without changing its observable behavior.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Refactoring&lt;/strong&gt; (&lt;em&gt;verb&lt;/em&gt;) -
To restructure software by applying a series of refactorings
without changing its observable behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So often developers refactor code and apply dozens of refactorings unconsciously!
We won't name the &lt;em&gt;small steps&lt;/em&gt;, and don't categorise our actions - we merely
crave clean code.
Often we forget that the code should roughly do the same things it did before,
i.e. &lt;strong&gt;the observable behaviour should not change&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In a nutshell, &amp;quot;Refactoring&amp;quot; teaches detecting a piece of code that needs refactoring,
determining which refactorings are necessary, applying them,
and most importantly - preserving the code behavior while doing all these.&lt;/p&gt;
&lt;div class="section" id="inside-the-book"&gt;
&lt;h2&gt;Inside the book&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Chapter 1&lt;/strong&gt; pulls the reader straight into refactoring example.
This chapter is &lt;a class="reference external" href="https://www.thoughtworks.com/content/dam/thoughtworks/documents/books/bk_Refactoring2-free-chapter_en.pdf"&gt;available for free download&lt;/a&gt;.
Before diving into the code, the author discusses the reasons for refactoring.
After all, a compiler doesn't care about the quality of our code.
It has no aesthetic judgement.
We like clean code because it is easier to comprehend and change.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
A poorly designed system is hard to
change—because it is difficult to figure out what to change and how these changes
will interact with the existing code to get the behaviour I want. And if it is hard
to figure out what to change, there is a good chance that I will make mistakes
and introduce bugs.&lt;/blockquote&gt;
&lt;p&gt;Fowler teaches how to improve the code without breaking it -
in tiny, explicit, consequential steps.
He emphasises the &lt;strong&gt;tests&lt;/strong&gt; as the cornerstone of successful refactoring.
If a piece of code has no tests, it's hard to tell whether its observed
behaviour changed after refactoring.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
When you have to add a feature to a program but the code is not structured
in a convenient way, first refactor the program to make it easy to add
the feature, then add the feature.&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Chapter 2 - &amp;quot;Principles in Refactoring&amp;quot;&lt;/strong&gt;,
discusses &lt;em&gt;why&lt;/em&gt; and &lt;em&gt;when&lt;/em&gt; we should refactor, the problems
and benefits of refactoring, its relationship to the software
development process in general and dozens of other aspects that one would
not even imagine.
This chapter also aids in explaining refactoring to а wide circle of people,
from junior developers to senior managers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chapter 3 - &amp;quot;Bad Smells in Code&amp;quot;&lt;/strong&gt;, is written in cooperation with Kent Beck.
While Chapter 2 talks of &lt;em&gt;the right time to refactor&lt;/em&gt;,
the third chapter describes the looks and smells of code that is crying for refactoring.
Best of all - the chapter is in plain English - not a single line of code in it!
&lt;em&gt;&amp;quot;Global data&amp;quot;&lt;/em&gt;, &lt;em&gt;&amp;quot;Repeated switches&amp;quot;&lt;/em&gt;, &lt;em&gt;&amp;quot;Temporary field&amp;quot;&lt;/em&gt;,
and many more - I bet you've met them before.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chapter 4 - &amp;quot;Building Tests&amp;quot;&lt;/strong&gt;, explains the value of self-testing code and
why effective refactoring is impossible without a reliable test suite.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
Refactoring is a valuable tool, but it can’t come alone.
To do refactoring properly, I need a solid suite of tests to spot my inevitable
mistakes.
Even with automated refactoring tools, many of my refactorings will still need
checking via a test suite.&lt;/blockquote&gt;
&lt;div class="section" id="the-catalogue"&gt;
&lt;h3&gt;The Catalogue&lt;/h3&gt;
&lt;p&gt;The rest of the book is a monumental catalogue of refactorings.
There are six chapters with more than 60 refactorings thoroughly broken down.
Fowler starts with a mix of refactorings that he considers the most useful and common,
such as &amp;quot;Extract function&amp;quot;, &amp;quot;Rename Variable&amp;quot;, &amp;quot;Introduce Parameter Object&amp;quot;.
Every following chapter reveals a group of related refactorings.&lt;/p&gt;
&lt;p&gt;Each refactoring is presented in a standard format:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;Name&lt;/strong&gt;. The name is important to building a vocabulary of refactorings.
Fowler refers to a refactoring by its name elsewhere in the book.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sketch&lt;/strong&gt;. The sketch shows a small code example of the transformation of the refactoring.
It does not explain what a refactoring is but
helps to understand and recognise a refactoring quickly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Motivation&lt;/strong&gt;. The motivation describes why the refactoring should be done
and the circumstances in which it should &lt;strong&gt;not&lt;/strong&gt;. While it's possible
to deal with a code smell via different refactorings, this section
describes the &amp;quot;flavour&amp;quot; of a code smell that requires the given refactoring.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mechanics&lt;/strong&gt;. The mechanics are a concise, step-­by-­step description of
how to carry out the refactoring.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Example&lt;/strong&gt;. The examples show how to apply the refactoring in code.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It's worth mentioning that the online catalogue of refactorings with
names and sketches is available for free at
&lt;a class="reference external" href="https://www.refactoring.com/catalog/"&gt;https://www.refactoring.com/catalog/&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="reading-the-book"&gt;
&lt;h3&gt;Reading the book&lt;/h3&gt;
&lt;p&gt;This book primarily appeals to seasoned developers.
One has to write thousands and read tens of thousands of lines of code before
she is able to detect code smells effortlessly.
The book won't make much sense for a junior developer
making his first steps in programming.&lt;/p&gt;
&lt;p&gt;Most of the refactorings would look familiar for the developers that
have been around the block.
Challenge yourself by trying to describe the exact mechanics of a refactoring before reading them.
I failed for almost all the refactorings, missing (not even realising) some steps
every time!
The examples help to map everything you've just learned about a refactoring
to real code.
It might be tedious to read every example section thoroughly -
after all, those are paper-printed code blocks.
But the book won't be complete without them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thoughts"&gt;
&lt;h3&gt;Thoughts&lt;/h3&gt;
&lt;p&gt;After I finished reading the book I felt that all my prior practical knowledge
and experience has been &amp;quot;rebased&amp;quot; on a solid theoretical foundation.
The book vocabulary is a ubiquitous language of the refactoring domain and
makes it so much easier to explain your intentions to colleagues
- especially when they also use the same vocabulary.
I highly recommend this book to software professionals
who want to improve and formalise their refactoring skills.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="review"/><category term="programming"/><category term="refactoring"/><category term="Martin Fowler"/><category term="Kent Beck"/></entry><entry><title>Hexagonal architecture and Python - Part II: Domain, Application Services, Ports and Adapters</title><link href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html" rel="alternate"/><published>2022-09-18T12:00:00+03:00</published><updated>2022-09-18T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2022-09-18:/posts/2022/09/18/hexarch_di_python_part_2.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;
&lt;img alt="Python logo in a hexagon with Roman II literal" class="align-center" src="https://zaurnasibov.com/articles/2022_09_18_hexarch_di_python_part_2/hexagonal-python-2.png" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Welcome to the second part of the article series, which cover principles of
Hexagonal architecture, Dependency Injection, Domain-Driven Design and applies
these all to Python and Django application design.&lt;/p&gt;
</summary><content type="html">&lt;img alt="Python logo in a hexagon with Roman II literal" class="align-center" id="hexarch-di-python-part-2" src="https://zaurnasibov.com/articles/2022_09_18_hexarch_di_python_part_2/hexagonal-python-2.png" /&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;Part I: Dependency Injection and componential architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II: Domain,  Application Services, Ports and Adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html"&gt;Part III: Persistence, Transactions, Exceptions and The Final Assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html"&gt;Part IV: Lightweight integration tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/tree/blog"&gt;The code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="update"&gt;
&lt;h2&gt;Update&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;February 2025&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Originally, I said that the domain model is the first thing to put in code.
Today, I always start with public interfaces, and in the case of RESTful services,
the API. Though what I consider &amp;quot;the right way&amp;quot; has changed, I left this article
almost intact, only commenting in a few places why API should be **coded*&lt;/em&gt; first.*&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="intro"&gt;
&lt;h2&gt;Intro&lt;/h2&gt;
&lt;p&gt;Now that you are familiar with the basic principles of Hexagonal architecture
(&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;see part I&lt;/a&gt;)
let's try implementing a Django-based application following these principles.
I've chosen Django for this exercise to demonstrate that even an opinionated framework is not an obstacle for Hexagonal architecture.
What about the other web frameworks, like FastAPI, Flask, AIOHTTP with SQLAchemy or a NoSQL data store?&lt;/p&gt;
&lt;p&gt;Hexagonal architecture painlessly decouples the business logic from the technical details of
HTTP communication, file system and database access, messaging and so on.
You can swap Django with FastAPI,
get rid of Django ORM and go with SQLAlchemy,
and the business logic implementation remains the same!&lt;/p&gt;
&lt;p&gt;The source code of the example is available at
&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/tree/blog"&gt;BasicWolf/hexagonal-architecture-django&lt;/a&gt;
Github repository.&lt;/p&gt;
&lt;div class="admonition tip"&gt;
&lt;p class="first admonition-title"&gt;Tip&lt;/p&gt;
&lt;p class="last"&gt;Clone the repository before reading further. The layered hexagonal architecture
means deeply nested python packages. It's much easier to follow the article when the example code is available locally.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="project-structure"&gt;
&lt;h2&gt;Project structure&lt;/h2&gt;
&lt;p&gt;A Django project is easily recognized by the top-level structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;src/
  hexarch_project/             # Django application essentials: wsgi.py, urls.py, settings.py
  myapp/
    migrations/                # Django migrations
    apps.py                    # Django app configuration (creates dependencies container instance)
    dependencies_container.py  # Dependencies container
    models.py                  # Django DB models (imports models from SPI adapters)
    urls.py                    # Django urls mappings
    ⋮
    application/               # application code; the structure follows the principles of hexagonal architecture
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Under the surface, the application &lt;em&gt;directory&lt;/em&gt; structure is much deeper.
From Python's perspective, all directories under &lt;tt class="docutils literal"&gt;application/&lt;/tt&gt; are &lt;strong&gt;namespace-packages&lt;/strong&gt;
i.e. there is no &lt;tt class="docutils literal"&gt;__init__.py&lt;/tt&gt; in them.
The namespace packages allow &lt;strong&gt;the tests packages structure to reflect the application packages structure&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The example application is structured as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;domain/            # Business domain models, services
  model/
  service/
port/              # API and SPI ports (interfaces)
  api/
  spi/
adapter/           # API and SPI ports implementation
  api/
    http/          # Django views and serializers
    messaging/
    ⋮
  spi/
    persistence/
      entity/      # Django models
      exceptions/  # Generic (django-independent) persistence exceptions
      repository/  # High-level persistence abstraction
    messaging/
    ⋮
service/           # Application services
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Notice that Django is used only in adapters.
Django Views are &lt;tt class="docutils literal"&gt;HTTP API&lt;/tt&gt; adapters and Django Models are
&lt;tt class="docutils literal"&gt;Persistence SPI&lt;/tt&gt; adapters.
The rest of the project is independent from the framework.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="use-case-upvote-an-article"&gt;
&lt;h2&gt;Use case: Upvote an Article&lt;/h2&gt;
&lt;p&gt;Now, let's take a look at an example use case.
Imagine a web blogging platform in development.
We want to add articles rating and let the users influence them.&lt;/p&gt;
&lt;p&gt;We gathered with the end-users, platform experts, QA, and other stakeholders
and drew some ideas:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Every article has a rating.&lt;/li&gt;
&lt;li&gt;A user can change an article rating.&lt;/li&gt;
&lt;li&gt;To change the article rating, a user either &amp;quot;upvotes&amp;quot; or &amp;quot;downvotes&amp;quot;.&lt;/li&gt;
&lt;li&gt;Users can vote for the article only if their &amp;quot;karma&amp;quot; (i.e. user rating) value is high enough, greater than 5.&lt;/li&gt;
&lt;li&gt;A user can vote once per article.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A user story is born:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nf"&gt;As a user of a blogging platform&lt;/span&gt;
&lt;span class="k"&gt;I &lt;/span&gt;&lt;span class="nf"&gt;want to give my vote,&lt;/span&gt;
&lt;span class="nf"&gt;So that the article&amp;#39;s rating changes.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="where-do-we-start"&gt;
&lt;h2&gt;Where do we start?&lt;/h2&gt;
&lt;p&gt;That's a simple question, isn't it?
Let's consider the options:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;strong&gt;Database&lt;/strong&gt;.
It is important to integrate early with the downstream dependencies.
The invisible bottlenecks could bring unpleasant surprises
if integration is postponed till the last moment.
Yet, a database is just storage and is usually located at
the bottom layer of the application infrastructure.
Do we really want to implement the database first and
let it influence the application implementation?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;strong&gt;Public API&lt;/strong&gt;. Public API is the contract with the outer world.
Its best design emerges when API consumers and producers collaborate.
After the API specification is ready, the consumers and the producer (our service) can
implement their part of the contract independently, and
start integration as early as possible, even when no domain/business logic
code exists yet!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;We should always start by studying the domain, building shared understanding
and deriving API from a detailed domain model. But when it comes to putting
things in code, nowadays I tend to release API integration components
as early as possible.
In the early stages, I hard-code the returned values and focus on making sure
that consumers can integrate. Only then do I start implementing the actual
business logic.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;strong&gt;Domain&lt;/strong&gt;. Starting with the domain model gives an advantage:
we can test our &lt;strong&gt;understanding&lt;/strong&gt; of the domain model, by expressing it
in the code.
Behaviour-driven development is essential at this stage.
BDD brings techniques and tools to test the domain model code against
the previously defined user stories.
The problem is that we don't have the means to interact with the model yet.
Which means that we have to go API first.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;However, the article continues as originally put - the Domain model
is implemented before API View. The flow of implementing the API first
is quite different from domain-first.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="the-domain"&gt;
&lt;h2&gt;The domain&lt;/h2&gt;
&lt;p&gt;A discussion between the developers, users and domain experts gives a birth to
a domain-specific language, where each term has a particular meaning.
We call this language - &lt;a class="reference external" href="https://www.martinfowler.com/bliki/UbiquitousLanguage.html"&gt;Ubiquitous language&lt;/a&gt; (UL).&lt;/p&gt;
&lt;p&gt;In Hexagonal architecture, the domain layer encapsulates the business logic and business processes.
On the code side, the UL terms are used in the names of classes, methods, and other code units.
Thus, by looking at the code, you can always tell how it is related to the problem domain.&lt;/p&gt;
&lt;p&gt;For example, a vote can be represented via the following enumeration
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/domain/model/vote.py#L4"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/domain/model/vote.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Vote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;UP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;up&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;DOWN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;down&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Karma is an explicit type alias
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/domain/model/karma.py"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/domain/model/karma.py&lt;/span&gt;

&lt;span class="n"&gt;Karma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Karma&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The most complex class of the domain is &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt;,
which represents a user that votes for an article.
The &lt;tt class="docutils literal"&gt;karma&lt;/tt&gt; value determines whether the user can vote.
We also need to know whether the user has already voted to prevent repeat voting.
Voting for an article produces a result:&lt;/p&gt;
&lt;img alt="uml diagram" class="align-center" src="https://zaurnasibov.com/images/4dee4275.png" /&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;
    &lt;span class="n"&gt;karma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Karma&lt;/span&gt;
    &lt;span class="n"&gt;votes_for_articles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ArticleVote&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;article_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vote&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_user_voted_for_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article_id&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;AlreadyVotedResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_karma_enough_for_voting&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;InsufficientKarmaResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;## IMPORTANT! The model state changes! ##&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;votes_for_articles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ArticleVote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="p"&gt;)&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;SuccessfullyVotedResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Notice that even the private methods &lt;tt class="docutils literal"&gt;_user_voted_for_article()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;_karma_enough_for_voting&lt;/tt&gt;
follow the domain language. A fellow developer can easily map the code
to the domain model and business rules.&lt;/p&gt;
&lt;p&gt;You may wonder what &lt;tt class="docutils literal"&gt;VoteForArticleResult&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;SuccessfullyVotedResult&lt;/tt&gt; are.
Recall the basics of Hexagonal architecture from
&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;Part I&lt;/a&gt;:
..&lt;/p&gt;
&lt;blockquote&gt;
Dependencies are directed from the outer layers to the inner centre.&lt;/blockquote&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;VoteForArticleResult&lt;/tt&gt;
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/domain/model/vote_for_article_result.py#L10"&gt;source&lt;/a&gt;]
is a domain data transfer object model.
It carries the voting result from the innermost application layer - the Domain
- to the outermost API adapter layer.&lt;/p&gt;
&lt;p&gt;Writing tests for a domain model is straightforward since &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;VotingUser.vote_for_article(...)&lt;/span&gt;&lt;/tt&gt; return value
is determined only by the &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; instance state and the method input values.
With meaningful fixtures names, tests turn into simple scenarios,
for example
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/tests/test_myapp/application/domain/model/test_voting_user.py#L16"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# tests/test_myapp/application/domain/model/test_voting_user.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_vote_for_article_twice_returns_already_voted_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;voting_user_who_has_voted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;article_id_for_which_user_has_voted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;a_vote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expected_already_voted_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AlreadyVotedResult&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;voting_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;voting_user_who_has_voted&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;article_id_for_which_user_has_voted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;a_vote&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;voting_result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected_already_voted_result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Once the domain model is fully implemented, we switch our focus to its
primary users - application services.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="application-service-a-skeleton"&gt;
&lt;h2&gt;Application service: a skeleton&lt;/h2&gt;
&lt;p&gt;Application services are the conductors that orchestrate processes and data flow in the application.
An application service implements one or more related use cases and invokes
all the necessary dependencies required to perform these use cases.
The service implementation can start with a single return statement only:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/service/article_rating_service.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&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;SuccessfullyVotedResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This dummy implementation is good enough to echo the commands back,
but much more needed to execute the use case.
For example, where does the application service get a &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt;?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="spi-ports"&gt;
&lt;h2&gt;SPI Ports&lt;/h2&gt;
&lt;p&gt;In Hexagonal Architecture, an application service communicates with the outer world
via Service Provider Interface (SPI) ports.
The application service fetches the users by &lt;tt class="docutils literal"&gt;user_id&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;article_id&lt;/tt&gt;.
That can be expressed in a &lt;tt class="docutils literal"&gt;FindVotingUserPort&lt;/tt&gt; interface as follows
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/port/spi/find_voting_user_port.py#L8"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/port/spi/find_voting_user_port.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;FindVotingUserPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;find_voting_user&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;article_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;We add &lt;tt class="docutils literal"&gt;FindVotingUserPort&lt;/tt&gt; as a dependency to the application service.
In practice, we add a respective field and a way to initialize it via constructor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/service/article_rating_service.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_find_voting_user_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FindVotingUserPort&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;find_voting_user_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FindVotingUserPort&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_find_voting_user_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_voting_user_port&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Can you tell, what actual implementation is behind that interface?
Is &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; found from a file? A database? Perhaps another HTTP endpoint?
Or a hard-coded value?
The application service does not care. It just makes a call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/service/article_rating_service.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;voting_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_find_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_voting_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Another responsibility of the service is to persist the voting results.&lt;/p&gt;
&lt;p&gt;It terms of &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Domain-driven_design"&gt;Domain-Driven Design&lt;/a&gt;,
&lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; is an &lt;a class="reference external" href="https://martinfowler.com/bliki/DDD_Aggregate.html"&gt;Aggregate root&lt;/a&gt;.
To update an article rating we have to persist a &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt; as a whole.
&lt;tt class="docutils literal"&gt;SaveVotingUserPort&lt;/tt&gt; takes care of that
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/port/spi/save_voting_user_port.py#L6"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/port/spi/save_voting_user_port.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;SaveVotingUserPort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;save_voting_user&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;voting_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="putting-the-service-pieces-together"&gt;
&lt;h2&gt;Putting the service pieces together&lt;/h2&gt;
&lt;p&gt;Finally, &lt;tt class="docutils literal"&gt;ArticleRatingService&lt;/tt&gt; has all the bits and pieces required to execute
the use case
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/service/article_rating_service.py#L16"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/service/article_rating_service.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleRatingService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_find_voting_user_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FindVotingUserPort&lt;/span&gt;
    &lt;span class="n"&gt;_save_voting_user_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SaveVotingUserPort&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;voting_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_find_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_voting_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;voting_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;voting_user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;voting_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SuccessfullyVotedResult&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_save_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save_voting_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;voting_user&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;voting_result&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;First, the service gets the required &lt;tt class="docutils literal"&gt;VotingUser&lt;/tt&gt;.
Next, the user votes for the article.
Last, the service checks whether the user has successfully voted and persists the user state.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Do you remember that an application service is supposed to orchestrate
the flow without any knowledge of its content?
You may have noticed, that our application service does not fulfil this
promise. The service controls the flow in &lt;tt class="docutils literal"&gt;match voting_result:&lt;/tt&gt; block.
I had to cheat here to make the code easier to follow and comprehend.
One of the purer alternatives is the
&lt;a class="reference external" href="https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-events-design-implementation"&gt;Domain events&lt;/a&gt;
mechanism.
It is a very interesting, but a huge topic, and unfortunately it falls out of the scope of this article.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="test-driven-application-services-development"&gt;
&lt;h2&gt;Test-driven application services development&lt;/h2&gt;
&lt;p&gt;Testing application service differs from testing a domain model.
Unlike a domain model, an application service has SPI dependencies, which should
be replaced with test doubles in each test.
That fact should not complicate the tests, though.
It is possible to construct and explicitly pass a dependency test double
and rely on default values for the rest of them.&lt;/p&gt;
&lt;p&gt;For example, we test that the service persists the voting user
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/tests/test_myapp/application/service/test_article_rating_service.py#L42"&gt;source&lt;/a&gt;].
The only dependency explicitly declared and passed to the service builder
is &lt;tt class="docutils literal"&gt;SaveVotingUserPortMock&lt;/tt&gt; test double.
All other dependencies are provided by the &lt;tt class="docutils literal"&gt;build_article_rating_service()&lt;/tt&gt; builder function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /tests/test_myapp/application/service/test_article_rating_service.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_voting_user_saved&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;vote_for_article_command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;saved_voting_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VotingUser&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;save_voting_user_port_mock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SaveVotingUserPortMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;article_rating_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_article_rating_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;save_voting_user_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;save_voting_user_port_mock&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;article_rating_service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vote_for_article_command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;save_voting_user_port_mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;saved_voting_user&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;saved_voting_user&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The application service which implements &lt;tt class="docutils literal"&gt;VoteForArticleUseCase&lt;/tt&gt; is ready.
Next, we implement the adapter that invokes the use case.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="http-api"&gt;
&lt;h2&gt;HTTP API&lt;/h2&gt;
&lt;p&gt;Let's start with the specification skeleton.
Notice how the request and responses are derived from the domain model:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;/article_vote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;post&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Vote for an article.&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;requestBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;application/json&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nt"&gt;$ref&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;#/components/schemas/Vote&amp;#39;&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;201&amp;#39;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Voted successfully.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;400&amp;#39;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Bad request. There was a domain constraint violation.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;409&amp;#39;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nt"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;Conflict. User has already voted.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;I deliberately omit the complete specification since
the topic is out of this article's scope.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Django Rest Framework is the obvious choice to facilitate a RESTful endpoint
implementation with Django.
Beside the request and response processing, the logic fits into few lines
of code
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/adapter/api/http/article_vote_view.py#L29"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/adapter/api/http/article_vote_view.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ArticleVoteView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APIView&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;vote_for_article_use_case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article_use_case&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vote_for_article_use_case&lt;/span&gt;
        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;post&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;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;vote_for_article_command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_read_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article_use_case&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vote_for_article&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;vote_for_article_command&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_build_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The intentions are:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Accept the HTTP request, deserialize and validate the request data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invoke the use case&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Serialize the result and render the response.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The view has one dependency: an object which implements &lt;tt class="docutils literal"&gt;VoteForArticleUseCase&lt;/tt&gt;
protocol
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/src/myapp/application/port/api/vote_for_article_use_case.py#L9"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /src/myapp/application/port/api/vote_for_article_use_case.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VoteForArticleUseCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;As we already know, the &lt;tt class="docutils literal"&gt;ArticleRatingService&lt;/tt&gt; has implemented this protocol
as is ready to be wired with the controller.&lt;/p&gt;
&lt;p&gt;Testing a HTTP controller is no different from testing an application service.
Every test injects a tuned double of the &lt;tt class="docutils literal"&gt;VoteForArticleUseCase&lt;/tt&gt; dependency
and asserts the expected state or behavior.
This makes the view testing times more lightweight compared to the traditional, spin-it-all-up Django app testing.&lt;/p&gt;
&lt;p&gt;For example, how to test a scenario, where a user tries to vote twice in a row?
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/tests/test_myapp/application/adapter/api/http/test_article_vote_view.py#L25"&gt;source&lt;/a&gt;]&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /tests/test_myapp/application/adapter/api/http/test_article_vote_view.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_user_votes_for_the_same_article_returns_conflict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;APIRequestFactory&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;## This is *the* view we are testing&lt;/span&gt;
    &lt;span class="n"&gt;article_vote_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArticleVoteView&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;## we are injecting a stub which always&lt;/span&gt;
        &lt;span class="c1"&gt;## returns AlreadyVotedResult (see below)&lt;/span&gt;
        &lt;span class="n"&gt;vote_for_article_use_case&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;VoteForArticleUseCaseAlreadyVotedStub&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;## A valid article vote is POSTed&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;article_vote_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;arf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;&amp;#39;/article_vote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s1"&gt;&amp;#39;user_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UserId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a3854820-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="s1"&gt;&amp;#39;article_id&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ArticleId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;dd494bd6-0000-0000-0000-000000000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                &lt;span class="s1"&gt;&amp;#39;vote&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Vote&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UP&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;json&amp;#39;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;## But the result is HTTP 409, as defined in the specification&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HTTPStatus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CONFLICT&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;status&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;409&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;detail&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;User &lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;a3854820-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt; has already voted&amp;quot;&lt;/span&gt;
                  &lt;span class="s2"&gt;&amp;quot; for article &lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;dd494bd6-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="se"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Cannot vote for an article&amp;quot;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And here is the &lt;tt class="docutils literal"&gt;VoteForArticleUseCaseAlreadyVotedStub&lt;/tt&gt;
[&lt;a class="reference external" href="https://github.com/BasicWolf/hexagonal-architecture-django/blob/blog/tests/test_myapp/application/adapter/api/http/test_article_vote_view.py#L148"&gt;source&lt;/a&gt;]:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# /tests/test_myapp/application/adapter/api/http/test_article_vote_view.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;VoteForArticleUseCaseAlreadyVotedStub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VoteForArticleUseCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;vote_for_article&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;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleCommand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;VoteForArticleResult&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;AlreadyVotedResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;article_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;article_id&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Please pause for a moment.
Does it take much effort to grok the test?
Did you notice that the test does not interact with rest of the application?
Did you also notice that it takes only five lines of code (three, if you put the
&lt;tt class="docutils literal"&gt;return&lt;/tt&gt; on a single line!) to mock &amp;quot;the rest of the application&amp;quot;?
The responsibilities are clearly decoupled, and
there is no need to set up a database or &lt;em&gt;any&lt;/em&gt; other service to test an HTTP endpoint.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-s-next"&gt;
&lt;h2&gt;What's next&lt;/h2&gt;
&lt;p&gt;This concludes Part II of the article series about Hexagonal Architecture
and Python and Django.
Part III will discuss how to use Django Models in SPIs, manage database
transactions and put all the application pieces together. Stay tuned!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="acknowledgments"&gt;
&lt;h2&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;I would like to express my very great appreciation to
&lt;a class="reference external" href="https://jereteittinen.info"&gt;Jere &amp;quot;Urokhtor&amp;quot; Teittinen&lt;/a&gt;
and &lt;a class="reference external" href="https://jarkko.org"&gt;Jarkko &amp;quot;jmp&amp;quot; Piiroinen&lt;/a&gt;
for reviewing the article and helping to improve it!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="architecture"/><category term="DDD"/><category term="dependency injection"/><category term="hexagonal architecture"/><category term="programming"/><category term="python"/></entry><entry><title>Good practices: Avoiding the use of test inputs in assertions</title><link href="https://zaurnasibov.com/posts/2021/11/10/good-practices-avoiding-the-use-of-test-inputs-in-assertions.html" rel="alternate"/><published>2021-11-10T12:00:00+02:00</published><updated>2021-11-10T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2021-11-10:/posts/2021/11/10/good-practices-avoiding-the-use-of-test-inputs-in-assertions.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2021/11/10/good-practices-avoiding-the-use-of-test-inputs-in-assertions.html"&gt;
&lt;img alt="Figure of eight know / https://freesvg.org/figure-of-eight-knot-vector-illustration / License: Public Domain" class="align-center" src="https://zaurnasibov.com/articles/2021-11-10-good-practices-avoiding-the-use-of-test-inputs-in-assertions/knot.png" style="width: 70%;" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;It might be very convenient to use the same fixtures in test
setup and assertions. This practice though is not as good as it looks
like at first glance.&lt;/p&gt;
</summary><content type="html">&lt;img alt="Figure of eight know / https://freesvg.org/figure-of-eight-knot-vector-illustration / License: Public Domain" class="align-center" src="https://zaurnasibov.com/articles/2021-11-10-good-practices-avoiding-the-use-of-test-inputs-in-assertions/knot.png" style="width: 70%;" /&gt;
&lt;p&gt;Imagine that we have to implement a &lt;em&gt;adding a title to a document&lt;/em&gt;.
The relationship between &lt;tt class="docutils literal"&gt;Title&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;Document&lt;/tt&gt; is straightforward
and we begin by writing a test:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_add_title_to_document&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Lorem Ipsum&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Take a minute to spot the weak points of the code above and let's discuss them.&lt;/p&gt;
&lt;div class="section" id="test-first-loop"&gt;
&lt;h2&gt;Test-First Loop&lt;/h2&gt;
&lt;p&gt;People who practice test-driven development sometimes focus on the details of
the process too much.
We start by writing a test. Sometimes we write it to the end, sometimes we
add small portions. The test fails and we write implementation to fix the failing
part.
The cycles repeats until the test is fully written and the implementation
fulfills the test. The satisfied developer moves to the next task, everyone
is happy.
Is there something missing though?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ultimate-test"&gt;
&lt;h2&gt;The Ultimate Test&lt;/h2&gt;
&lt;p&gt;If someone asks you, what was the ultimate purpose of any test
(we're speaking of software development of course) what would you answer?&lt;/p&gt;
&lt;p&gt;I think that the goal of any test is to &lt;strong&gt;confirm the relationship
between certain inputs and outputs of a routine&lt;/strong&gt;. The routine size doesn't matter
- it could be as small as a function in a unit test or as big as a complex behavior
of multiple services in an end-to-end test.&lt;/p&gt;
&lt;p&gt;This brings us back to the code above. The input is &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Title(&amp;quot;lorem&lt;/span&gt; ipsum&amp;quot;)&lt;/tt&gt;.
What about the output?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="outputs-inputs"&gt;
&lt;h2&gt;Outputs ≠ Inputs&lt;/h2&gt;
&lt;p&gt;The output of the test above is also the input. That is the biggest evil
here. There is absolutely no way to fail this test by modifying the input:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_add_title_to_document&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dolor sit amet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# changes don&amp;#39;t affect test behaviour&lt;/span&gt;

    &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;However, the test fails if input and output are separated:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_add_title_to_document&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dolor sit amet&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Lorem Ipsum&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# hooray, this fails!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="test-first-loop-extended-edition"&gt;
&lt;h2&gt;Test-First Loop: Extended edition&lt;/h2&gt;
&lt;p&gt;My colleague &lt;a class="reference external" href="https://jereteittinen.info"&gt;Jere Teittinen&lt;/a&gt;
taught me an amazingly simple and useful trick about writing tests.
When you have completed writing a test assertion and the routine behind it,
&lt;strong&gt;change the inputs or outputs to verify that the assertion fails&lt;/strong&gt;.
This is an important step which &lt;strong&gt;protects the test from tailored routine
implementation&lt;/strong&gt;.
Such routine is able to fulfill the test only with the original inputs
and outputs. You shake them a bit and everything falls apart like
a house of cards.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="good practices"/><category term="programming"/><category term="python"/><category term="testing"/><category term="unit tests"/></entry><entry><title>Hexagonal architecture and Python - Part I: Dependency Injection and componential architecture</title><link href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html" rel="alternate"/><published>2021-10-30T22:30:00+03:00</published><updated>2021-10-30T22:30:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2021-10-30:/posts/2021/10/30/hexarch_di_python_part_1.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;
&lt;img alt="Python logo in a hexagon" class="align-center" src="https://zaurnasibov.com/articles/2021_10_30_hexarch_di_python_part_1/hexagonal-python.png" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Welcome to articles series which cover the principles of
Hexagonal architecture, talks of Dependency Injection, and its usage in
these to Python and Django application design.&lt;/p&gt;
</summary><content type="html">&lt;img alt="Python logo in a hexagon" class="align-center" src="https://zaurnasibov.com/articles/2021_10_30_hexarch_di_python_part_1/hexagonal-python.png" /&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2021/10/30/hexarch_di_python_part_1.html"&gt;Part I: Dependency Injection and componential architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/09/18/hexarch_di_python_part_2.html"&gt;Part II: Domain,  Application Services, Ports and Adapters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2022/12/31/hexarch_di_python_part_3.html"&gt;Part III: Persistence, Transactions, Exceptions and The Final Assembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://zaurnasibov.com/posts/2025/05/10/hexarch-python-part-4-lightweight-integration-tests.html"&gt;Part IV: Lightweight integration tests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Time flies awfully fast!
Two and a half years ago I left the world of Django and found myself in the
world of Spring Boot, Kotlin and Java.
It was a genuine cultural shock.
An extensive amount of new knowledge bombarded my brains.
Sometimes it was so furious, that I wanted to run back to
the beloved and bytewise familiar Python ecosystem.
Inversion of Control (IoC) was the hardest topic to digest.
Automated Dependency Injection (DI) felt like black magic,
compared to Django's direct approach. Spring Boot behemoth framework consumed me in nightmares. But all the effort was worth it.&lt;/p&gt;
&lt;p&gt;We designed and implemented the application following Hexagonal architecture rules. And the final challenge was getting rid of the old &amp;quot;implement
a backlog of features&amp;quot; habit in place of Domain-Driven Design (DDD).&lt;/p&gt;
&lt;p&gt;Our product is rapidly growing in size and complexity.
Still, it is easy to maintain, support and develop
- thanks to the solid foundation.
The code is expressive and comprehensible.
The components are easily interchangeable.
By all means this product is better than anything
previosly written by the team members.&lt;/p&gt;
&lt;p&gt;I look behind and see all the gaps in my experience
which did not allow solving business problem as elegantly.
Dear fellow Pythonista, I hope
this short articles series about Hexagonal architecture
would help you to achieve the same without going through my struggle.&lt;/p&gt;
&lt;div class="section" id="dependency-injection"&gt;
&lt;h2&gt;Dependency Injection&lt;/h2&gt;
&lt;p&gt;You know what Dependency Injection (DI) is, don't you?
Sure you do, even if you can't recall the explicit definition.
Let's see what are the pros and cons of this approach (a pattern, if you prefer).&lt;/p&gt;
&lt;p&gt;Imagine that we need a function which sends ALARM messages to a message bus.
The first iteration is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;my_cool_messaging_library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_message_bus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;message_bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_message_bus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;message_bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Is there anything wrong with &lt;tt class="docutils literal"&gt;send_alert()&lt;/tt&gt; function?
It depends upon &lt;tt class="docutils literal"&gt;message_bus&lt;/tt&gt; object, but this dependency
is hidden from the caller.
What if you'd like to use another message bus?
How about the level of magic required to test this function?
Did I just hear &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;mock.patch(...)&lt;/span&gt;&lt;/tt&gt;?
Ladies and gentlemen, this is going south, let's try a different way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;my_cool_messaging_library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message_bus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&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;message_bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This small change in function signature is a big change of paradigm.
The caller sees that &lt;tt class="docutils literal"&gt;send_alert()&lt;/tt&gt; function &lt;strong&gt;depends&lt;/strong&gt; upon
&lt;tt class="docutils literal"&gt;MessageBus&lt;/tt&gt; object (viva type annotations!).
All implicit mocking bells and whistles are gone in favour of
explicit and clean code.
Sounds too good to be true?
Have a look:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_send_alert_sends_message_to_alert_topic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;message_bus_mock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MessageBusMock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;send_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message_bus_mock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hacking attempt detected!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;message_bus_mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_to_topic&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;message_bus_mock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_message&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hacking attempt detected!&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MessageBusMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send&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;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_to_topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But doesn't this mean that we have to pass an instance of &lt;tt class="docutils literal"&gt;MessageBus&lt;/tt&gt; to
&lt;tt class="docutils literal"&gt;send_alert()&lt;/tt&gt; function on each call? Isn't that cumbersome?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;send_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_message_bus&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Stackoverflow is down&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Let's try solving this problem by means of OOP:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AlertDispatcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_message_bus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;message_bus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message_bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_bus&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message_bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;alert_dispatcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AlertDispatcher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_message_bus&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;alert_dispatcher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Oh no, yet another dependency!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now &lt;tt class="docutils literal"&gt;AlertDispatcher&lt;/tt&gt; class &lt;strong&gt;depends&lt;/strong&gt; on an object of type &lt;tt class="docutils literal"&gt;MessageBus&lt;/tt&gt;.
We &lt;strong&gt;inject&lt;/strong&gt; this dependency when creating an &lt;tt class="docutils literal"&gt;AlertDispatcher&lt;/tt&gt; object
by passing the dependency into constructor.
We have &lt;strong&gt;wired&lt;/strong&gt; (not coupled!) the object and its dependency.&lt;/p&gt;
&lt;p&gt;At this point the focus switches from &lt;tt class="docutils literal"&gt;message_bus&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;alert_dispatcher&lt;/tt&gt;.
This &lt;strong&gt;component&lt;/strong&gt; may be required in different parts of the application.
Which means that there should be a global context which holds and provides
the object.
Let's first discuss the nature of components and components wiring.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="componential-architecture"&gt;
&lt;h2&gt;Componential Architecture&lt;/h2&gt;
&lt;p id="messagebus"&gt;We didn't emphasize dependencies types while speaking of dependency injection.
But you might have guessed that &lt;tt class="docutils literal"&gt;MessageBus&lt;/tt&gt; is just an abstraction,
an interface or a protocol &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.
Somewhere the application defines:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&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;message&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="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p id="memorymessagebus"&gt;There is also a simple implementation of &lt;tt class="docutils literal"&gt;MessageBus&lt;/tt&gt; in the project.
It stores the incoming messages in a &lt;tt class="docutils literal"&gt;list&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MemoryMessageBus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sent_messages&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="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&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;messagge&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sent_messages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p id="dispatchalertusecase"&gt;In the same manner, an abstract use case scenario is decoupled from a
business-driven implementation:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# An abstract use case&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DispatchAlertUseCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;typing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dispatch_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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="k"&gt;pass&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# A concrete implementation in a service.&lt;/span&gt;
&lt;span class="c1"&gt;# Note that a service may implement multiple related use cases at a time.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AlertDispatcherService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DispatchAlertUseCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;_message_bus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;message_bus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MessageBus&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message_bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message_bus&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dispatch_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_message_bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p id="chatopscontroller"&gt;Next, let's add a controller which accepts HTTP requests and invokes
&lt;tt class="docutils literal"&gt;DispatchAlertUseCase&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ChatOpsController&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;dispatch_alert_use_case&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DispatchAlertUseCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dispatch_alert_use_case&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dispatch_alert_use_case&lt;/span&gt;

    &lt;span class="nd"&gt;@post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/alert)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;alert&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;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dispatch_alert_use_case&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatch_alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;HTTP_ACCEPTED&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Finally, let's connect all the pieces together:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;my_favourite_http_framework&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;http_server&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;message_bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MemoryMessageBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;alert_dispatcher_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AlertDispatcherService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message_bus&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chat_opts_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatOpsController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alert_dispatcher_service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;http_server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;How would a rational and clear-minded developer react to this?
She would call it overengineered and overcomplicated, no less!
Which is indeed true. On the first glance, everything above fits into a short
HTTP handler:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/alert)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;bus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MemoryMessageBus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;bus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;message&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;HTTP_ACCEPTED&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Is it short and simple? Absolutely!
Is it maintainable? Hardly.
But why?
Because the components are strongly coupled in the code.
By blending everything in a single function we tightly couple
domain workflow and message bus implementation.
And that's half the trouble.
The worst part is that we
&lt;em&gt;melted and buried business logic in technical details&lt;/em&gt;.
Don't get me wrong, such code has the right to exist.
Yet its existence in a rapidly growing application will
soon end up in a maintenance hell.&lt;/p&gt;
&lt;p&gt;Back to the componential architecture.
What are the advantages?&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Components are &lt;strong&gt;isolated&lt;/strong&gt; and are not directly dependent.
Instead they are &lt;strong&gt;wired via abstractions&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Every component works in certain boundaries and &lt;strong&gt;has a single responsibility&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This means that components are immensely testable:
either in full isolation or in a combination using test doubles.
There is no need to explain that testing  isolated parts of a program
is easier compared to testing it as a whole.
Your TDD approach improves from inaudible &amp;quot;well, we do tests...&amp;quot;
to sonorous &amp;quot;tests-driven and test-first development&amp;quot;.&lt;/li&gt;
&lt;li&gt;It is easy to substitute components, thanks to abstract dependencies.
In the example above &lt;tt class="docutils literal"&gt;MemoryMessageBus&lt;/tt&gt; could be replaced with
&lt;tt class="docutils literal"&gt;DbMessageBus&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;FileMessageBus&lt;/tt&gt; or anything else.
The caller of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;message_bus.send(...)&lt;/span&gt;&lt;/tt&gt; should not care.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suddenly it dawns upon you:
&amp;quot;That sounds like... SOLID?&amp;quot;
Hell yeah!
It is almost what Uncle Bob would call a
&lt;a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;Clean Architecture&lt;/a&gt;.
I encourage you to read his article, before moving towards our end goal -
Hexagonal architecture.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="architecture-is-about-intent"&gt;
&lt;h2&gt;Architecture is about intent&lt;/h2&gt;
&lt;p&gt;One of my favourite Uncle Bob quotes on software architecture is
&amp;quot;Architecture is about intent&amp;quot;.&lt;/p&gt;
&lt;p&gt;What do you see on this screenshot?&lt;/p&gt;
&lt;img alt="Typical Django project" class="align-center" src="https://zaurnasibov.com/articles/2021_10_30_hexarch_di_python_part_1/django_project.png" /&gt;
&lt;p&gt;No wonder if you recognized a &amp;quot;typical Django application&amp;quot;.
Brilliant!
Can you also tell what does this application do?
If you can, my sincere congratulations - you are level 80 telepathist.
Personally I have no clue whatsoever - that is a screenshot
of a random Django application from Github.&lt;/p&gt;
&lt;p&gt;Robert Martin develops the idea
&lt;a class="reference external" href="https://www.youtube.com/watch?v=WpkDN78P884"&gt;further&lt;/a&gt;.
Take a look at a floor architecture plan and guess what the building is intended for:&lt;/p&gt;
&lt;img alt="Typical Django project" class="align-center" src="https://zaurnasibov.com/articles/2021_10_30_hexarch_di_python_part_1/library_floor_paln.jpg" /&gt;
&lt;details&gt;
&lt;summary&gt;&lt;a&gt;Answer&lt;/a&gt;&lt;/summary&gt;&lt;p&gt;That is a floor plan of &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Helsinki_Central_Library_Oodi"&gt;Oodi Library&lt;/a&gt; in Helsinki.&lt;/p&gt;
&lt;/details&gt;&lt;p&gt;I hope this tiny puzzle was easy to solve and you got the main idea:
architecture should meet us at the gate, literally after &lt;tt class="docutils literal"&gt;git clone&lt;/tt&gt;.
Isn't it great when the source code is organized in such way
that the purpose and the meaning of each file, class, function and
any other object lies on the surface?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hexagonal-architecture-of-ports-and-adapters"&gt;
&lt;h2&gt;Hexagonal architecture of Ports and Adapters&lt;/h2&gt;
&lt;p&gt;&amp;quot;We use the Hexagonal architecture of ports and adapters&amp;quot; - how we start
describing the architecture application to the new team members.
It follows by showing a weird Cthulhu-like picture:&lt;/p&gt;
&lt;img alt="Hexagonal architecture" class="align-center" src="https://zaurnasibov.com/articles/2021_10_30_hexarch_di_python_part_1/hexagon.png" /&gt;
&lt;p&gt;Alistair Cockurn, the inventor of &amp;quot;Hexagonal architecture&amp;quot; term explains
that &amp;quot;hexagon&amp;quot; is not strictly necessary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The hexagon is not a hexagon because the number six is important,
but  rather to allow the people doing the drawing to have room
to insert  ports and adapters as they need,
not being constrained by a  one-dimensional layered drawing.&lt;/p&gt;
&lt;p&gt;The term ‘’hexagonal architecture’’  comes from this visual effect.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;&lt;a class="reference external" href="https://alistair.cockburn.us/hexagonal-architecture/"&gt;Alistair Cockburn&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You may also recall the terms like
&amp;quot;Onion architecture&amp;quot; or &amp;quot;Ports and Adapters&amp;quot; mentioned in Uncle Bob's
&lt;a class="reference external" href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;&amp;quot;Clean archcitecture&amp;quot;&lt;/a&gt;
article.
All these terms describe a way to organize application architectecture in
layers, with dependecies directed to the center.
(We noticed though, that &lt;em&gt;hexagon&lt;/em&gt; and &lt;em&gt;ports and adapters&lt;/em&gt; are much simpler to
imagine and explain compared to more abstract terms like &amp;quot;clean&amp;quot; or &amp;quot;onion&amp;quot;).&lt;/p&gt;
&lt;p&gt;The outer layer of the application - &lt;em&gt;adapters&lt;/em&gt; - interacts with the outer world.
The inner layer - &lt;em&gt;domain&lt;/em&gt; and &lt;em&gt;domain services&lt;/em&gt; - contains the business logic.
The connecting layer in between is &lt;em&gt;application services&lt;/em&gt;.
The components in each layer are designed to have low coupling and high cohesion &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Domain&lt;/strong&gt; layer - is the heart of the application.
The business rules are defined here.
The names of classes, methods, functions, constants and other objects resemble
those of the problem domain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Application Programming Iterface (API) adapters&lt;/strong&gt;
are the components which convey commands and queries from the
outer world to the application through &lt;em&gt;API ports&lt;/em&gt;.
Hence, &lt;strong&gt;API ports&lt;/strong&gt; are interfaces through which the application is controlled
and queried.
In the &lt;em&gt;Componential architecture&lt;/em&gt; described above, the &lt;a class="reference internal" href="#dispatchalertusecase"&gt;DispatchAlertUseCase&lt;/a&gt; is
an &lt;em&gt;API port&lt;/em&gt; and &lt;a class="reference internal" href="#chatopscontroller"&gt;ChatOpsController&lt;/a&gt; is an &lt;em&gt;API adapter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Provider Interface (SPI) adapters&lt;/strong&gt; are the components which convey
the application commands and queries to the outer world.
Hence, &lt;strong&gt;SPI ports&lt;/strong&gt; are interfaces through which commands and queries are
passed to &lt;em&gt;SPI adapters&lt;/em&gt;.
In the &lt;em&gt;Componential architecture&lt;/em&gt;, the &lt;a class="reference internal" href="#messagebus"&gt;MessageBus&lt;/a&gt; is an &lt;em&gt;SPI port&lt;/em&gt; and
its implementation &lt;a class="reference internal" href="#memorymessagebus"&gt;MemoryMessageBus&lt;/a&gt; is an &lt;em&gt;SPI adapter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Application services&lt;/strong&gt; are the conductors which glue domain and ports
performing use case scenarios. They are supposed to orchestrate the whole
transaction, e.g. load data for the domain to use, call functions
which perform domain logic, persist the results and publish events.&lt;/p&gt;
&lt;p&gt;There is one important rule to remember about hexagonal architecture:
&amp;quot;&lt;em&gt;Dependencies are directed from the outer layers to the inner center.&lt;/em&gt;&amp;quot;
In practice this means that &lt;em&gt;adapters are aware of domain objects,
but domain should not know of adapters or ports&lt;/em&gt;.
It's also important to clarify that since adapters belong to the &lt;em&gt;Adapters
layer&lt;/em&gt;, they may call each-other directly.
The cases for this are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;API adapter calls SPI adapter&lt;/em&gt;.
- Think of HTTP GET requests which end up querying a database:
It doesn't make sense to reach database through the domain layer making tons
of objects mappings on the way. It's much more efficient for a controller
to call the specific &lt;em&gt;SPI port&lt;/em&gt; directly.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;SPI adapter calls SPI adapter.&lt;/em&gt; - Think of an database adapter which
calls other adapters and aggregates all the results before returning it.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;API adapter calls API adapter.&lt;/em&gt; - Probably the least useful. Handy,
if you need to redirect calls from one API adapter to the other.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;SPI adapter calls API adapter&lt;/em&gt; - AVOID. Such calls is unnecessary
and creates call loops in the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And... THAT IS IT!
The basic principles of Hexagonal architecture of ports and adapters
are surprisingly simple.
This kind of architecture works well in application with complex problem domain.
But it is an overkill, if everything you need is an
&amp;quot;HTTP interface for a database&amp;quot;.&lt;/p&gt;
&lt;p&gt;We are now ready to dive into building a Hexagonal architecture -based
Django applications.
Stay tuned for part II.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Though &lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0544/"&gt;PEP-544&lt;/a&gt; Protocols
are about structural subtying. Another option to mimic interfaces is
to either use abstract classes with abstract methods.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;p class="first"&gt;Cohesion and coupling:&lt;/p&gt;
&lt;ul class="last simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://devopedia.org/cohesion-vs-coupling"&gt;Devopedia: Cohesion vs. Coupling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://enterprisecraftsmanship.com/posts/cohesion-coupling-difference/"&gt;Cohesion and Coupling: the difference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="architecture"/><category term="DDD"/><category term="dependency injection"/><category term="hexagonal architecture"/><category term="programming"/><category term="python"/></entry><entry><title>Turn the Ship Around!: A True Story of Turning Followers into Leaders - book review</title><link href="https://zaurnasibov.com/posts/2021/10/22/turn_the_ship_around_short_review.html" rel="alternate"/><published>2021-10-22T12:00:00+03:00</published><updated>2021-10-22T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2021-10-22:/posts/2021/10/22/turn_the_ship_around_short_review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2021/10/22/turn_the_ship_around_short_review.html"&gt;
&lt;img alt="Turn the Ship Around!: A True Story of Turning Followers into Leaders book cover" class="align-center" src="https://zaurnasibov.com/articles/2021_10_22_turn_the_ship_around/turn_the_ship_around_cover.webp" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;&amp;quot;Turn The Ship Around!&amp;quot; is an exceptional book. It narrates a story of a
poor-performing submarine becoming the best in a short period of time.
It teaches the mechanisms of such transformation which involve the
leader and the team alike.&lt;/p&gt;
</summary><content type="html">&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Whatever sense we have of thinking we know something is a barrier
to continued learning.&lt;/em&gt;&lt;/p&gt;
&lt;p class="right"&gt;(David Marquet, &amp;quot;Turn The Ship Around!&amp;quot;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;
&lt;img alt="Turn the Ship Around!: A True Story of Turning Followers into Leaders book cover" class="align-center" src="https://zaurnasibov.com/articles/2021_10_22_turn_the_ship_around/turn_the_ship_around_cover.webp" /&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;What does it take to turn a nuclear submarine around?&amp;quot;&lt;/em&gt; sprung up in my head,
when I saw the cover of the book for the first time. It turns out, the book
wasn't literally about turning the ship around. Or rather the definition of
a &amp;quot;ship&amp;quot; was not a &amp;quot;nuclear submarine&amp;quot;.&lt;/p&gt;
&lt;p&gt;What does it take to challenge the decision making and leadership mechanisms
in an organization as old and solid as U.S. Navy? Any why should these mechanisms
change in the first place?&lt;/p&gt;
&lt;p&gt;In December 1998, Captain David Marquet was ordered to
take command over the &lt;em&gt;SSN Santa Fe&lt;/em&gt; - a nuclear-powered fast attack submarine.
She and her crew were to be ready for combat deployment in six months.
That was not an ordinary task.
Not only Captain Marquet previously spent half a year getting ready to command
&lt;em&gt;SSN Olympia&lt;/em&gt; - a submarine completely different from technical perspective,
he was also assigned to command &amp;quot;&lt;em&gt;The Santa Fe&lt;/em&gt;&amp;quot; - the worst-performing submarine
in the navy at a time.&lt;/p&gt;
&lt;p&gt;However, that rapid change of plan was not coincidental nor random.
During his earlier career and training Marquet has experienced and identified the
limitations of &amp;quot;One leader commands them all&amp;quot; or broadly &amp;quot;Leader - Follower&amp;quot;
approach. &lt;em&gt;The follower learns to rely on the leader to make all decisions rather
than to fully engage with the work process to help make the organization
run as efficiently as possible. One of the factors that makes this top-down
leadership approach appealing is the induced numbness. It absolves subordinates
of the hard work of thinking, making decisions, and being responsible and
accountable&lt;/em&gt;.
&lt;em&gt;Santa Fe&lt;/em&gt; was a ship where &lt;em&gt;everyone below the captain and the department heads
had their brain shut off&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Captain Marquet was committed to &amp;quot;turn &lt;em&gt;Santa Fe&lt;/em&gt; around&amp;quot;.
He describes how he needed to let go of old ideas to make room for new ones.
He would make small evolutionary steps to build the bridge from &amp;quot;leader-follower&amp;quot;
to the supreme &amp;quot;leader-leader&amp;quot; approach.
The core of the leader-leader model is giving employees &lt;strong&gt;control&lt;/strong&gt; over what they
work on and how they work. It means letting them make meaningful decisions.
The two enabling pillars are &lt;strong&gt;competence&lt;/strong&gt; and &lt;strong&gt;clarity&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Marquet discovered that leader-leader structures are significantly more resilient,
and they do not rely on the designated leader always being right.
Moreover, they spawn additional leaders throughout the organization naturally.&lt;/p&gt;
&lt;p&gt;&amp;quot;Turn The Ship Around!&amp;quot; is a story of how a mediocre crew that focused
on avoiding mistakes became a crew thriving to achieve excellence.
Marquet does a fantastic storytelling, fusing the narrative with
practical analysis and guide. Every chapter focuses on a set small
set of challenges that the crew and the captain of &lt;em&gt;Santa Fe&lt;/em&gt; had to face
and the solution they've come up with. All solutions are further described
as practical &amp;quot;mechanisms&amp;quot;.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ultimately, this book is a call to action, a manifesto, for all those
frustrated workers and bosses for whom the current leadership structure
just isn’t working.&lt;/em&gt;&lt;/p&gt;
&lt;p class="right"&gt;(David Marquet, &amp;quot;Turn The Ship Around!&amp;quot;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="section" id="a-crew-a-tribe"&gt;
&lt;h2&gt;A crew? - A Tribe!&lt;/h2&gt;
&lt;p&gt;What I personally find great about &lt;em&gt;Santa Fe's&lt;/em&gt; journey is that it resembles
a journey through the stages of tribal relationships as described in
&amp;quot;Tribal Leadership&amp;quot; &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.
The crew of &lt;em&gt;Santa Fe&lt;/em&gt;, was at stage 2: &amp;quot;My life sucks&amp;quot; when Captain Marquet took over.
The crew wanted change, even if they didn’t know quite how to do it. And since
the leader-follower approach in place, they always had the boss,
the ultimate decision maker - merely the captain to blame for every problem.&lt;/p&gt;
&lt;p&gt;Captain Marquet was able to &lt;em&gt;to tap into the existing energy of
the command, discover the strengths, and remove barriers to further progress&lt;/em&gt;.
Marquet's determination, commitment and leadership helped the crew to reach
the highest tribal stages: Stage 4 &amp;quot;We're great&amp;quot; - and ultimately
Stage 5 &amp;quot;Life is Great&amp;quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="thoughts"&gt;
&lt;h2&gt;Thoughts&lt;/h2&gt;
&lt;p&gt;A good leader always remembers what needs to be done, follows up the execution
to make sure that it was unimpeachable. A great leader doesn't have to remember
everything or follow up every step the team makes. Instead, the leader employs
practices which ensure that the team can perform flawlessly without a leader
being present.
He or she are the part of the team where every member trusts each-other to do
their job. That trust comes from the team being competent, being able to make
decisions, clearly understanding the goals on all levels - from personal to
organizational. That trust means that every single member of the crew is a leader.&lt;/p&gt;
&lt;p&gt;What kind of a leader are you? A leader that tells what should be done,
controls the execution hides the bigger picture since
&amp;quot;it's not their concern&amp;quot;? A leader who wants to be followed?
Or a leader who clarifies the bigger picture,
helps building competence and lets the team figure out the best way to perform
the job? A leader who trusts and is trusted in return? A leader who spawns leaders?&lt;/p&gt;
&lt;p&gt;Thanks to David Marquet I made my mind. How about you?&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://www.triballeadership.net"&gt;Tribal Leadership: Leveraging Natural Groups to Build a Thriving Organization
(Dave Logan, John King, Halee Fischer-Wright)&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="leadership"/></entry><entry><title>Accelerate: The Science of Lean Software and DevOps - book review</title><link href="https://zaurnasibov.com/posts/2021/06/23/accelerate_book_review.html" rel="alternate"/><published>2021-06-23T12:00:00+03:00</published><updated>2021-06-23T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2021-06-23:/posts/2021/06/23/accelerate_book_review.html</id><summary type="html">&lt;a class="reference external image-reference first" href="https://zaurnasibov.com/posts/2021/06/23/accelerate_book_review.html"&gt;
&lt;img alt="Accelerate book cover" class="align-center" src="https://zaurnasibov.com/articles/2021_06_23_accelerate/accelerate_cover.jpg" style="width: 25%;" /&gt;
&lt;/a&gt;
&lt;p class="last"&gt;Are you familiar with the gut feeling that the software development
practices around you could be better? What if I told you that there
is a solid scientific study on practices of low and high performing
technology organizations?&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="longing-for-improvement"&gt;
&lt;h2&gt;Longing for improvement&lt;/h2&gt;
&lt;p&gt;Are you familiar with the gut feeling that the software development
practices around you could be better?
Sometimes the desired improvements are small and obvious.
They are not very hard to implement and have a quick return of investment.&lt;/p&gt;
&lt;p&gt;For example, adding a vulnerability scanner to a CI pipeline prevents using
dependencies with known CVEs.
A code formatter which applies the rules for every source file save operation -
brings determinism and keeps team members from nagging about style.
Even a low disk space alarm configured long time ago
could save you from major embarrassment and business losses.&lt;/p&gt;
&lt;p&gt;Other improvements are not that easy.
Core dependencies being dramatically outdated since new versions break
compatibility?
Painful deployment with downtime lasting for days?
Features being developed by single developers for months and living in a branch
for all the that time?
Backlog growing indefinitely.
Bugs, bugs and even more bugs pouring in every day?
I'd be glad to tell that the above is a horror story, and it never happens in
reality. But you and I both know the sad truth.
Worse - when everyone in the development
department agrees that something should be done, but the time is never right.
Thousands of software businesses have to deal with stories like this every day.&lt;/p&gt;
&lt;p&gt;There is no silver bullet to fix all the issues in your organization.
But we are not armless in the matter.
What if you don't need to guess what should or could be improved?
What if there is a solid scientific study on practices of
high performing technology organizations?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="accelerate"&gt;
&lt;h2&gt;Accelerate&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Accelerate&lt;/strong&gt; by Nicole Forsgren, Jez Humble and Gene Kim is a book concluding
a four-year research into capabilities and practices
of software development practices.
There were over 23000 survey responses from over 2000 unique
and diverse organizations from around the world collected during the research.
It uncovered 24 key capabilities that drive improvement in
software delivery performance. Some of these capabilities are:
&lt;strong&gt;continuous delivery&lt;/strong&gt; and &lt;strong&gt;trunk-based development&lt;/strong&gt;,
&lt;strong&gt;loosely coupled architecture&lt;/strong&gt; and &lt;strong&gt;customer feedback&lt;/strong&gt;,
&lt;strong&gt;work-in-progress limits&lt;/strong&gt; and &lt;strong&gt;transformational leadership&lt;/strong&gt;.&lt;/p&gt;
&lt;img alt="Accelerate book cover" class="align-center" src="https://zaurnasibov.com/articles/2021_06_23_accelerate/accelerate_cover.jpg" style="width: 40%;" /&gt;
&lt;p&gt;&amp;quot;Accelerate&amp;quot; doesn't have all the answers and is not a guidebook.
But it clearly describes the differences between low and high -performing
organizations and teams. It explains in detail how capabilities are related
and how each capability affects performance and
how leadership is essential for transformation.
Being said, not every capability is easy to measure.
You can quickly estimate how long it takes to deliver a committed piece of code
to the customer. But how do you measure culture?&lt;/p&gt;
&lt;p&gt;The second part of the book may help you find the answer.
While the first part is about the study results, it's the second part which
explains the methods used in the research and dives deep into the science
behind conducted surveys.&lt;/p&gt;
&lt;p&gt;The third part is a life example story of ING  Netherlands.
It tells how leadership, management, and team  practices work together
bringing a traditional banking business into the digital age.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="verdict"&gt;
&lt;h2&gt;Verdict&lt;/h2&gt;
&lt;p&gt;There is no verdict. This book is truth based on facts.
Although not a long one, my career has been among low, average and great
performing teams.
I mentally applied everything said in the book to my experience,
and boy it is accurate!
There is really no excuse for an organization to ignore this study or
delay applying the practices ASAP.
If you want to stay in the game, you have to &lt;strong&gt;Accelerate&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Books"/><category term="book"/><category term="software development"/><category term="accelerate"/></entry><entry><title>Alarms and dashboards</title><link href="https://zaurnasibov.com/posts/2021/06/04/alarms_and_dashboards.html" rel="alternate"/><published>2021-06-04T12:00:00+03:00</published><updated>2021-06-04T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2021-06-04:/posts/2021/06/04/alarms_and_dashboards.html</id><summary type="html">&lt;p class="first last"&gt;Ranting about alarms and dashboards&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Dashboard is a great tool to show information in a human-friendly manner.
Yet, it is useless as a monitoring tool.
Hanging a big shiny screen in the middle of the room, with bars, plots,
charts and lots of other cool stuff is spectacular.
But it won't help you to catch an issue in a timely manner.
That is because you can't watch the screen all the time, don't you?&lt;/p&gt;
&lt;p&gt;The solution is obvious - alarms.
Alarms are meant to warn you when the situation is exceptional or
something is about to go south. When a service fails.
When your disk space is running low.
When a request processing time takes too long.
When there is an error in logs.&lt;/p&gt;
&lt;p&gt;And then, you actually need a dashboard to query the history
of the parameters in trouble.
You'd want to see the trend of free disk space - did it happen suddenly,
or it's been filling up in a linear manner?
Maybe you have to wipe some old data?
Perhaps there was a temporal network error?
How many times that error happened lately?&lt;/p&gt;
&lt;p&gt;Alarm can be dangerous.
When you get too many alarms they slip through.
Too many &amp;quot;usual&amp;quot; alarms turn into annoying buzz which is soon ignored.
The solution is to temporarily disable the unnecessary alarms.
Do keep in mind that
&lt;strong&gt;an alarm could be disabled only when you are actively fixing the problem&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is nothing new.
Have you seen Ron Howard's &amp;quot;Apollo 13&amp;quot; film?
Remember the CO2 alarm indicator lighting up and the crew checking
the CO2 levels on the gauge?&lt;/p&gt;
&lt;img alt="CO2 Indicator | Apollo 13 (2005)" class="align-center" src="https://zaurnasibov.com/articles/2021_06_04_alarms_and_dashboards/apollo_13_co2_indicator.jpg" style="width: 50%;" /&gt;
&lt;p&gt;Can you imagine the crew constantly checking those values
to make sure that CO2 levels are acceptable instead?
What about other critical indicators?
Of course not.&lt;/p&gt;
&lt;img alt="CO2 Gauge | Apollo 13 (2005)" class="align-center" src="https://zaurnasibov.com/articles/2021_06_04_alarms_and_dashboards/apollo_13_co2_gauge.jpg" style="width: 50%;" /&gt;
&lt;p&gt;There are alarms to draw attention and dashboards to help dealing with the alarm as fast as possible.&lt;/p&gt;
</content><category term="Articles"/><category term="rants"/><category term="alarm"/><category term="dashboard"/><category term="DevOps"/><category term="errors"/></entry><entry><title>Concrete Settings: a new way to manage configurations in Python projects</title><link href="https://zaurnasibov.com/posts/2020/07/11/concrete_settings.html" rel="alternate"/><published>2020-07-11T13:06:00+03:00</published><updated>2020-07-11T13:06:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2020-07-11:/posts/2020/07/11/concrete_settings.html</id><summary type="html">&lt;p&gt;After two years of developing a hobby project,
I am proud to announce &lt;strong&gt;Concrete Settings&lt;/strong&gt; -
a new configuration management library for Python projects.&lt;/p&gt;
&lt;p&gt;Concrete Settings was born as an effort to improve configuration handling in
a huge decade-old Django application with exceedingly bloated &lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt;.
Remember that &lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt; starts …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After two years of developing a hobby project,
I am proud to announce &lt;strong&gt;Concrete Settings&lt;/strong&gt; -
a new configuration management library for Python projects.&lt;/p&gt;
&lt;p&gt;Concrete Settings was born as an effort to improve configuration handling in
a huge decade-old Django application with exceedingly bloated &lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt;.
Remember that &lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt; starts with Django configuration only?
What could go wrong if you start adding &lt;em&gt;application&lt;/em&gt; settings to the file?
One setting, two settings, four...&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;FEATURE_X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;
&lt;span class="n"&gt;FEATURE_Y_ENABLED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;FEATURE_Z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;square&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;In time there were so many settings, that developers loose track of them.
The documentation was scattered around issues tracking tool and outdated wiki pages.
There was little or no settings validation - sometimes customers were getting
&lt;tt class="docutils literal"&gt;HTTP 500 - Internal Server Error&lt;/tt&gt; due to typo in a setting value.&lt;/p&gt;
&lt;p&gt;Concrete Settings does its best to tackle these problems.&lt;/p&gt;
&lt;div class="section" id="why"&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;I was thinking a lot of a developer's and end-user's experience.
How would Concrete Settings library differ from the existing solutions?&lt;/p&gt;
&lt;p&gt;After months of experimenting and juggling ideas, the following
ideas laid the foundation:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Settings with their validation rules and documentation are defined in classes.&lt;/li&gt;
&lt;li&gt;Validation can happen independently from the application, allowing early fails.&lt;/li&gt;
&lt;li&gt;Settings definitions can be nested and mixed.&lt;/li&gt;
&lt;li&gt;Application can read settings from developer-defined sources, like
yaml / json / python files, environmental variables etc.&lt;/li&gt;
&lt;li&gt;All these are based on Python metaclassing and other capabilities
to minimize the amount of code written by an end-developer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From an end-user's perspective:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Settings are defined in sources. User works with &lt;tt class="docutils literal"&gt;application.yml&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;configuration.json&lt;/tt&gt;
environmental variables or custom solutions instead of overbloated &lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;An immediate and verbose feedback is received if settings values are invalid.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="enough-words-show-me-the-code"&gt;
&lt;h2&gt;Enough words, show me the code!&lt;/h2&gt;
&lt;p&gt;Let's take a look at a simple example and see the bells and whistles
(aka cool features) that are in the box.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# app_settings.py&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;concrete_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;concrete_settings.contrib.sources&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;EnvVarSource&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;#: Whether debug mode is enabled&lt;/span&gt;
    &lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;#: HTTP server host&lt;/span&gt;
    &lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;

    &lt;span class="c1"&gt;#: HTTP server listening port&lt;/span&gt;
    &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="c1"&gt;# Verify settings definition and construct settings object&lt;/span&gt;
&lt;span class="n"&gt;app_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Read settings from sources&lt;/span&gt;
&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;settings.yml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EnvVarSource&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raise_exception&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&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="s2"&gt;&amp;quot;Server HOST is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&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="s2"&gt;&amp;quot;Server PORT is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&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="s2"&gt;&amp;quot;DEBUG is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEBUG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;An end-user is happy with the default &lt;tt class="docutils literal"&gt;HOST&lt;/tt&gt; value, but wants to override
the rest of the configuration in &lt;tt class="docutils literal"&gt;settings.yml&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;8081&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;and set &lt;tt class="docutils literal"&gt;DEBUG=true&lt;/tt&gt; via an environmental variable.&lt;/p&gt;
&lt;p&gt;The output in this case would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;Server HOST is 127.0.0.1 (HTTP server host)       # default value&lt;/span&gt;
&lt;span class="go"&gt;Server PORT is 8080 (HTTP server listening port)  # settings.yml&lt;/span&gt;
&lt;span class="go"&gt;DEBUG is True (Whether debug mode is enabled)     # environmental variable&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="document-via-sphinx-style-docstrings"&gt;
&lt;h2&gt;Document via sphinx-style docstrings&lt;/h2&gt;
&lt;p&gt;Concrete Settings allows documenting settings via
&lt;tt class="docutils literal"&gt;#:&lt;/tt&gt; Sphinx-style comments:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;#: HTTP server host&lt;/span&gt;
&lt;span class="c1"&gt;#: Format: IPv4 address encoded in a string&lt;/span&gt;
&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Documentation can be also passed in an explicit Setting definition.&lt;/p&gt;
&lt;p&gt;Let's compare these explicit and implicit definitions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;#: HTTP server port&lt;/span&gt;
    &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

    &lt;span class="n"&gt;HOST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s1"&gt;&amp;#39;127.0.0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;type_hint&lt;/span&gt;&lt;span class="o"&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;doc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;HTTP server host&amp;#39;&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Explicit or implicit - the extracted docstring, is stored
to &lt;tt class="docutils literal"&gt;Setting.__doc__&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;However, wouldn't you agree that &lt;tt class="docutils literal"&gt;PORT&lt;/tt&gt; documentation is
way more pleasant to read and maintain?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="validate-settings-early-and"&gt;
&lt;h2&gt;Validate settings early and...&lt;/h2&gt;
&lt;p&gt;What if a user makes a typo and the supplied port is not an integer?&lt;/p&gt;
&lt;p&gt;Let's change a value in &lt;tt class="docutils literal"&gt;settings.yml&lt;/tt&gt; from the first example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;8081&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;8081&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Running the first example again would raise an exception:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;concrete_settings.exceptions.ValidationError: PORT: Expected value of type `&amp;lt;class &amp;#39;int&amp;#39;&amp;gt;` got value of type `&amp;lt;class &amp;#39;str&amp;#39;&amp;gt;`.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The validation error message is generated by the default &lt;tt class="docutils literal"&gt;ValueTypeValidator&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="add-custom-validators-with-style"&gt;
&lt;h2&gt;... add custom validators with style!&lt;/h2&gt;
&lt;p&gt;Let's craft a validator which checks that port number is equal or greater than &lt;tt class="docutils literal"&gt;8000&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;concrete_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;port_validator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;ignore&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="mi"&gt;8000&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;65535&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Expected value in range 8000..65535&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;#: HTTP server listening port&lt;/span&gt;
    &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="nd"&gt;@validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_validator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;--- I know you are scrolling, but have you noticed this?&lt;/span&gt;


&lt;span class="n"&gt;app_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;settings.yml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here we use a decorator-like syntax of so-called &lt;em&gt;behaviors&lt;/em&gt;
(actually it's a matrix multiplication operator in this case :).&lt;/p&gt;
&lt;p&gt;Let's test it out by changing &lt;tt class="docutils literal"&gt;PORT&lt;/tt&gt; value in &lt;tt class="docutils literal"&gt;settings.yml&lt;/tt&gt; to 80:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;80&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The result of running the snippet above is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;False&lt;/span&gt;
&lt;span class="go"&gt;{&amp;#39;PORT&amp;#39;: [&amp;#39;Expected value in range 8000..65535&amp;#39;]}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;If you are still uncomfortable with &amp;#64;behaviors - there is an explicit way to
add validators to settings. Simply pass &lt;tt class="docutils literal"&gt;validators&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;Setting&lt;/tt&gt; constructor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;#: HTTP server listening port&lt;/span&gt;
    &lt;span class="n"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Setting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port_validator&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="helpful-hierarchies"&gt;
&lt;h2&gt;Helpful hierarchies&lt;/h2&gt;
&lt;p&gt;I never liked settings names like &lt;tt class="docutils literal"&gt;DB_HOST_ADDRESS&lt;/tt&gt;.
Why have flat settings names, with feature, sub-feature,
configuration, sub-configuration... in them?&lt;/p&gt;
&lt;p&gt;Concrete Settings prefers composition over flat-style settings declaration,
though it provides both extension and grouping
mechanism for settings. For example, let's define database and logging
settings in separate classes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;concrete_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DBSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;USER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;alex&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;PASSWORD&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;secret&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;localhost@5432&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LoggingSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;LEVEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;INFO&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;FORMAT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;%(asctime)s&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="si"&gt;%(levelname)-8s&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="si"&gt;%(name)-15s&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="si"&gt;%(message)s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DBSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;LOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoggingSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;app_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOG&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LEVEL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;At first glance, there is nothing special about this code.
What makes it special and somewhat confusing is
that class &lt;tt class="docutils literal"&gt;Settings&lt;/tt&gt; is a subclass of &lt;tt class="docutils literal"&gt;Setting&lt;/tt&gt;!
Hence, nested Settings behave and can be treated
as Setting descriptors - have validators, documentation
or bound behavior.&lt;/p&gt;
&lt;p&gt;Additionally, validating top-level settings
automatically cascades to all nested settings.
The following example ends up with a validation error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;concrete_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Settings&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;DBSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DBSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;app_settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppSettings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app_settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raise_exception&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gt"&gt;Traceback (most recent call last):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="gr"&gt;concrete_settings.exceptions.ValidationError&lt;/span&gt;: &lt;span class="n"&gt;DB: Expected value of type `&amp;lt;class &amp;#39;str&amp;#39;&amp;gt;` got value of type `&amp;lt;class &amp;#39;int&amp;#39;&amp;gt;`&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Finally, the settings can be read from a similarly nested structure. For example &lt;tt class="docutils literal"&gt;settings.json&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;DB&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;USER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;or environmental variable &lt;tt class="docutils literal"&gt;DB_USER&lt;/tt&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="in-a-retrospective"&gt;
&lt;h2&gt;In a retrospective&lt;/h2&gt;
&lt;p&gt;This project took a long time to develop. What I did right was
no releasing an unfinished and buggy library. That is probably also
what I did wrong. Trying to polish everything before the first
public release without getting any users feedback is not the best
way to go. Hopefully, there will be feedback and the project
would steer towards its users needs and wishes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="let-s-start"&gt;
&lt;h2&gt;Let's start!&lt;/h2&gt;
&lt;p&gt;Install it via pip:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;concrete-settings
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;and check out the
&lt;a class="reference external" href="https://concrete-settings.readthedocs.org"&gt;documentation&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="library"/><category term="python"/><category term="concrete settings"/></entry><entry><title>Is classical music performed too fast?</title><link href="https://zaurnasibov.com/posts/2018/04/25/is_classical_music_performed_too_fast.html" rel="alternate"/><published>2018-04-25T21:00:00+03:00</published><updated>2018-04-25T21:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2018-04-25:/posts/2018/04/25/is_classical_music_performed_too_fast.html</id><summary type="html">&lt;p class="first last"&gt;Harder, Better, Faster, Stronger... wait - that is Daft Punk.
Though classical music seems to follow.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Every now and then, being at home with kids I put on some music they've never heard before.
I always try different genres - rock, blues, jazz, even hip hop.
This time I've chosen one of my favorites, the renowned classic of classics:
Antonio Vivaldi's Four Seasons.&lt;/p&gt;
&lt;p&gt;But the first notes of the &amp;quot;Spring&amp;quot; made me shiver.
&amp;quot;This doesn't sound right! It sounds... too fast?&amp;quot;
Seems that the first search results in Spotify yielded the recording of 1999,
conducted by &lt;em&gt;Fabio Biondi, Europa Galante orchestra&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But there were more to discover. &lt;em&gt;&amp;quot;Sinkovsky Plays and Sings Vivaldy&amp;quot;&lt;/em&gt; was the
next search result. Oh my! What is your rush man? It is played so fast that
makes enjoying the music impossible. It felt like I've been given the best
of the world's delicacies and have only two minutes to taste them all.
Don't get me wrong - the technique is impressive! But where is the soul
in all that?&lt;/p&gt;
&lt;p&gt;And there are many more performances that sound too paced.
For example &lt;em&gt;La Serenissima / Adrian Chandler&lt;/em&gt; (2015), and even &lt;em&gt;Nigel Kennedy&lt;/em&gt; (1989).&lt;/p&gt;
&lt;p&gt;I made a simple experiment: searched for &amp;quot;four seasons summer g minor&amp;quot; in Spotify
and sorted the results by duration.
After manually narrowing the results to the third part of the &amp;quot;Summer&amp;quot; -
I found myself gazing upon a 45 seconds difference between the slowest
(&lt;em&gt;Takako Nishizaki, Capella Istropolitana, Stephen Gunzenhauser&lt;/em&gt;)
and the fastest (&lt;em&gt;Giuliano Carmignola, Venice Baroque Orchestra&lt;/em&gt;) performances!
From 3m 07s to 2m 22s!&lt;/p&gt;
&lt;p&gt;My overall impression of listening to the faster-paced performances was
somewhat of standing in the middle of a stock exchange at a rush hour.
Instruments are screaming, vulgarly interrupting each-other, not letting
one another to finish the parts.&lt;/p&gt;
&lt;p&gt;Is it the speed of our age that influences tempo that much?
Or is it me, being used to the slower performance of &amp;quot;Four Seasons&amp;quot;?&lt;/p&gt;
</content><category term="Articles"/><category term="music"/><category term="classical"/></entry><entry><title>Blogging with Pelican</title><link href="https://zaurnasibov.com/posts/2017/04/25/blogging-with-pelican.html" rel="alternate"/><published>2017-04-25T21:00:00+03:00</published><updated>2017-04-25T21:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2017-04-25:/posts/2017/04/25/blogging-with-pelican.html</id><summary type="html">&lt;p class="first last"&gt;&lt;a class="reference external" href="https://getpelican.com"&gt;Pelican&lt;/a&gt; is a perfect blogging platform for programmers and computer geeks. My blog has been powered by Pelican for three years and it has been a pleasant experience. If you are looking forward to start a blog, or just thinking of changing a platform, why not give it a try?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external" href="https://getpelican.com"&gt;Pelican&lt;/a&gt; is a static site generator,
that requires no database or server-side logic.
It is also an amazing blogging platform and as of April 2017,
my blog is powered by Pelican.
At this point, people stare at me with &amp;quot;&lt;em&gt;ORLY?&lt;/em&gt;&amp;quot; expression on their faces.
Why not Wordpress, Tumblr, Facebook or any other 3rd-party blogging platform?&lt;/p&gt;
&lt;p&gt;I tried Google Blogger a decade ago. Back then, the editor
was extremely basic and sometimes one had to edit HTML manually
to get the required visual representation.
Then there was Wordpress. It was rather nice, with all its integrated
features and thousands of free themes and plugins.
However, self-hosted Wordpress can be a painful experience.
Even with automatic updates I ended up with hacked blog
sending spam emails in background.&lt;/p&gt;
&lt;p&gt;Around 2010 I wrote a simple blogging engine in Python/Django.
That was a nice programming exercise (you've got to try
it at least once in a lifetime!) but it required even more
maintenance: upgrading Django, fixing bugs, adding new features,
fixing styles in theme etc.&lt;/p&gt;
&lt;p&gt;Free time was becoming luxury, so I started looking for
a solution which would take care of all the routine, which requires little or
no maintenance at all and which would be preferably written in a familiar
programming language.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://tinkerer.me/"&gt;Tinkerer&lt;/a&gt; was the first static blog generator
I encountered. It works fine,
however there are some configuration limitations e.g. the output
files and directory structure is generated in a certain hard-coded way.
Pelican on the other hand has a very wide range of configurable options
and provides great extensibility API for developers. As of April 2017
there are over 120 various 3rd-party plugins and over
100 user-made themes.
Needless to say, Pelican has a large and active community!&lt;/p&gt;
&lt;p&gt;That is something one might expect from a good blogging platform.
Is there something what makes blogging via Pelican a remarkable experience
for computer geeks?&lt;/p&gt;
&lt;p&gt;For starters, you write the content in &lt;a class="reference external" href="http://docutils.sourceforge.net/rst.html"&gt;reStructuredText&lt;/a&gt;,
&lt;a class="reference external" href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt;,
or &lt;a class="reference external" href="http://www.methods.co.nz/asciidoc/"&gt;AsciiDoc&lt;/a&gt;  formats (btw, this blog is written in reStructuredText).
The code highlight comes right out of the box. You can publish the content in different languages.
You can even have multiple authors in a blog!
&lt;em&gt;Static&lt;/em&gt; output means, that there is very little or no maintenance and
no more blog engine upgrades because of yet-another-critical-security-issue.
Thanks to the community, I don't have to worry about the themes and
once the static output is generated, it can be published literally anywhere, on any web server.&lt;/p&gt;
&lt;p&gt;So begins the new era of my blog. Powered by Pelican!&lt;/p&gt;
&lt;p&gt;P.S.&lt;/p&gt;
&lt;p&gt;Thanks to Alexandre Vicenzi for &lt;a class="reference external" href="https://github.com/alexandrevicenzi/flex"&gt;Flex&lt;/a&gt; theme!&lt;/p&gt;
</content><category term="Articles"/><category term="blogging"/><category term="pelican"/><category term="python"/></entry><entry><title>The ultimate guide to Python decorators</title><link href="https://zaurnasibov.com/posts/2017/01/22/the_ultimate_guide_to_python_decorators.html" rel="alternate"/><published>2017-01-22T23:00:00+02:00</published><updated>2017-01-22T23:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2017-01-22:/posts/2017/01/22/the_ultimate_guide_to_python_decorators.html</id><summary type="html">&lt;p class="first last"&gt;Decorators are one of the most beautiful feature of Python
programming language. They can make code easy-readable
and maintainable. Nevertheless, their usage may seem tricky
and mysterious in the beginning.
This is a guide to the world of decorators. I hope that
you will feel like a pro and have no questions left about them
after exploring this article.&lt;/p&gt;
</summary><content type="html">&lt;div class="contents topic" id="contents"&gt;
&lt;p class="topic-title"&gt;&lt;a class="reference internal" href="#top"&gt;Contents&lt;/a&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#introduction-to-decorators" id="toc-entry-1"&gt;Introduction to decorators&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#historical-background" id="toc-entry-2"&gt;Historical background&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#geting-to-know-decorators" id="toc-entry-3"&gt;Geting to know decorators&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#closures-1" id="toc-entry-4"&gt;Closures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#your-first-decorator-1" id="toc-entry-5"&gt;Your first decorator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#examples" id="toc-entry-6"&gt;Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#chaining-decorators-1" id="toc-entry-7"&gt;Chaining decorators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#decorators-with-arguments-1" id="toc-entry-8"&gt;Decorators with arguments&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#wrapping-functions-properly-1" id="toc-entry-9"&gt;Wrapping functions properly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#decorators-and-arguments-1" id="toc-entry-10"&gt;Decorators and arguments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#class-as-a-decorator" id="toc-entry-11"&gt;Class as a decorator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#function-decorators-vs-class-decorators" id="toc-entry-12"&gt;Function-decorators vs. class-decorators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#decorating-methods-1" id="toc-entry-13"&gt;Decorating methods&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#self-and-method-decorators" id="toc-entry-14"&gt;Self and method decorators&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#decorating-classes-1" id="toc-entry-15"&gt;Decorating classes&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="reference internal" href="#example-registering-a-plugin" id="toc-entry-16"&gt;Example: Registering a plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#finale" id="toc-entry-17"&gt;Finale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#references" id="toc-entry-18"&gt;References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="introduction-to-decorators"&gt;
&lt;h2&gt;Introduction to decorators&lt;/h2&gt;
&lt;div class="section" id="historical-background"&gt;
&lt;h3&gt;Historical background&lt;/h3&gt;
&lt;p&gt;It all started with discussion on how-to turn the following syntax
into something nice:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;This is class C&amp;#39;&lt;/span&gt;

    &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;staticmethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This is an absolutely valid code, however declaring &lt;tt class="docutils literal"&gt;info&lt;/tt&gt; as a
static method requires wrapping it as &lt;tt class="docutils literal"&gt;info = staticmethod(info)&lt;/tt&gt;.
Inconvenient, isn't it?&lt;/p&gt;
&lt;p&gt;In case you are not familiar with &lt;tt class="docutils literal"&gt;staticmethod()&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;: it is a builtin
function which accepts a function as an argument and creates a static method for the class.
This is all done via &lt;a class="reference external" href="https://docs.python.org/3/howto/descriptor.html"&gt;descriptors protocol&lt;/a&gt;,
but no need to go that deep today. At this point, &lt;tt class="docutils literal"&gt;info()&lt;/tt&gt; can be called as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;This is class C&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;After months of discussion, analysis and research
&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0318/"&gt;PEP 318 -- Decorators for Functions and Methods&lt;/a&gt;
was finally accepted. Since Python 2.4 decorators turned the code above into&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

   &lt;span class="nd"&gt;@staticmethod&lt;/span&gt;  &lt;span class="c1"&gt;# this is a decorator&lt;/span&gt;
   &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;This is class C&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="geting-to-know-decorators"&gt;
&lt;span id="what-decorators-are"&gt;&lt;/span&gt;&lt;h3&gt;Geting to know decorators&lt;/h3&gt;
&lt;p&gt;A decorator is a syntactic sugar of calling a function which
accepts another function as an argument and returns either the
same function or another callable. &lt;em&gt;Note: this
definition is not complete and will be expanded further in the
article&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Take a look at these nice decorators examples:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Django web framework view decorators&lt;/span&gt;
&lt;span class="nd"&gt;@login_required&lt;/span&gt;
&lt;span class="nd"&gt;@require_GET&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# I can assume now that only GET requests&lt;/span&gt;
    &lt;span class="c1"&gt;# from a logged in user make it this far.&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;


&lt;span class="c1"&gt;# Flask web microframework routing&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hello World!&amp;quot;&lt;/span&gt;


&lt;span class="c1"&gt;# Standard library unit tests&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="nd"&gt;@skipUnless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;win&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;requires Windows&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_windows_support&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;# windows specific testing code&lt;/span&gt;
        &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;No doubt, decorators improve the readability of code dramatically.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="closures-1"&gt;
&lt;span id="closures"&gt;&lt;/span&gt;&lt;h3&gt;Closures&lt;/h3&gt;
&lt;p&gt;Let's take a look at a practical example to see how decorators work from
the inside. Imagine that you want to log all the
arguments' values and the return value of a
&lt;tt class="docutils literal"&gt;send_message(sender, receiver, &lt;span class="pre"&gt;text='')&lt;/span&gt;&lt;/tt&gt; function calls to &lt;tt class="docutils literal"&gt;stdout&lt;/tt&gt;.
This can be simply done via &lt;tt class="docutils literal"&gt;print()&lt;/tt&gt; as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;send_message was called&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;The arguments are sender=&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;, receiver=&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;, text=&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;The return value is &amp;quot;SENT&amp;quot;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SENT&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;However, consider that you now have to do the same for dozen other
functions, all with different arguments and return values.
First, let's do this without decorators:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message_with_log&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;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send_message&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="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;send_message was called&amp;#39;&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;ret&lt;/span&gt;

&lt;span class="c1"&gt;# Important substitution&lt;/span&gt;
&lt;span class="n"&gt;send_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send_message_with_log&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;To make &lt;tt class="docutils literal"&gt;send_message_with_log&lt;/tt&gt; more generic, a technique called
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Closure_(computer_programming)"&gt;closure&lt;/a&gt;
is used as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&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="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt; was called&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&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;ret&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="n"&gt;send_message_with_log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;send_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send_message_with_log&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here, value of &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; is stored in lexical scope of &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt;, which means
that after &lt;tt class="docutils literal"&gt;send_message_with_log = log_fn(send_message)&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;send_message_with_log&lt;/tt&gt; variable
has a value of the &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt; function with &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt; stored in
&lt;tt class="docutils literal"&gt;f&lt;/tt&gt; variable. Finally, the &lt;em&gt;original&lt;/em&gt; &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt; is substituted.
In a single line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Calling &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt; will produce the following output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="go"&gt;send_message was called&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Note, that &lt;tt class="docutils literal"&gt;log_fn&lt;/tt&gt; is now generic and can be used to log any functions' calls.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="your-first-decorator-1"&gt;
&lt;span id="your-first-decorator"&gt;&lt;/span&gt;&lt;h3&gt;Your first decorator&lt;/h3&gt;
&lt;p&gt;Now we are ready to turn &lt;tt class="docutils literal"&gt;log_fn&lt;/tt&gt; into a decorator.
Let's write it down and analyze its code line-by-line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&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="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt; was called&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@log_fn&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;SENT&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;1. def log_fn(f):&lt;/tt&gt; - a decorator is defined. It is a function
which accepts a single argument - another function.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;2. def &lt;span class="pre"&gt;wrapper(*args,&lt;/span&gt; **kwargs):&lt;/tt&gt; - an internal function (a closure technique)
which wraps calls to function &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; with custom logic. For a moment let's
skip the body of &lt;tt class="docutils literal"&gt;wrapper()&lt;/tt&gt; and proceed to the end of &lt;tt class="docutils literal"&gt;log_fn()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;7. return wrapper&lt;/tt&gt; - the return value of the decorator. It returns
a callable, which is usually an internal wrapper function.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;9. &amp;#64;log_fn&lt;/tt&gt; - at this point decorator is called with
&lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt; as an argument. This is equivalent to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="c1"&gt;# send_message is substituted&lt;/span&gt;
&lt;span class="n"&gt;send_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Pay attention to the &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt; function, which is returned
by &lt;tt class="docutils literal"&gt;log_fn()&lt;/tt&gt; and assigned to &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt;. What happens
to the original &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt;? Let's get back to the body of
&lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;3. ret = &lt;span class="pre"&gt;f(*args,&lt;/span&gt; **kwargs)&lt;/tt&gt; - here the original &lt;tt class="docutils literal"&gt;f&lt;/tt&gt; function
is called. At this point, &lt;tt class="docutils literal"&gt;f == send_message&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;4. &lt;span class="pre"&gt;print('{}&lt;/span&gt; was &lt;span class="pre"&gt;called'.format(f.__name__))&lt;/span&gt;&lt;/tt&gt; - a simple logging
to stdout, which prints &lt;tt class="docutils literal"&gt;&amp;quot;send_message was called&amp;quot;&lt;/tt&gt; each time the
function is called&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;5. return ret&lt;/tt&gt; - the return value of the original function
call is returned&lt;/p&gt;
&lt;p&gt;Finally, let's update the decorator to make it more useful and fulfill
the original requirements of logging the function call with the
arguments and the return value:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&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;sargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&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;arg&lt;/span&gt; &lt;span class="ow"&gt;in&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;skwargs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;, &amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&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;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{name}&lt;/span&gt;&lt;span class="s1"&gt;( &lt;/span&gt;&lt;span class="si"&gt;{sargs}&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="si"&gt;{skwargs}&lt;/span&gt;&lt;span class="s1"&gt; ) =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{ret}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;sargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sargs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;skwargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;skwargs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;repr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;)&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;ret&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;So, the output of calling the decorated &lt;tt class="docutils literal"&gt;send_message&lt;/tt&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;alice&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bob&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;send_message( &amp;#39;alice&amp;#39;, &amp;#39;bob&amp;#39;, text=&amp;#39;Hello!&amp;#39; ) =&amp;gt; SENT&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="examples"&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;p&gt;Decorator syntax allows quick and clear extension of the wrapped
functions. Its beauty is in simplicity: by writing a single line declaration
one can embed powerful functionality while keeping the code clean and neat.&lt;/p&gt;
&lt;p&gt;Let's explore decorators possibilities by writing a couple of
decorators which might be handy in development.&lt;/p&gt;
&lt;div class="section" id="debug-on-error"&gt;
&lt;h4&gt;debug_on_error&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pdb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;debug_on_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Drop to pdb debugger on exception&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;try&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;f&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;except&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;pdb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post_mortem&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;wrapper&lt;/span&gt;

&lt;span class="c1"&gt;# usage&lt;/span&gt;
&lt;span class="nd"&gt;@debug_on_error&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This decorator allows dropping into debugger the moment an error
occurs in a function call. For example running the following code
in ipython3:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;div&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="go"&gt;&amp;lt;ipython-input-2-cd786e30d343&amp;gt;(3)div()&lt;/span&gt;
&lt;span class="go"&gt;-&amp;gt; return x / y&lt;/span&gt;
&lt;span class="go"&gt;(Pdb) ?&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="timeit"&gt;
&lt;h4&gt;timeit&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Measure an execution time of the wrapped function&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;tick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&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;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&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;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;() execution time: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt; s.&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tick&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;ret&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="c1"&gt;# example&lt;/span&gt;
&lt;span class="nd"&gt;@timeit&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This decorator prints the amount of seconds passed between function
call and return events. It is helpful to measure a function's execution
time and find performance bottlenecks. Let's run an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10e6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="go"&gt;sum_up_to() execution time: 0.0465855598449707 s.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="chaining-decorators-1"&gt;
&lt;span id="chaining-decorators"&gt;&lt;/span&gt;&lt;h3&gt;Chaining decorators&lt;/h3&gt;
&lt;p&gt;Imagine that you want to log the function call with &lt;tt class="docutils literal"&gt;log_fn&lt;/tt&gt; and
at the same time profile it with &lt;tt class="docutils literal"&gt;timeit&lt;/tt&gt; decorators.
Just chain the decorators! For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@timeit&lt;/span&gt;
&lt;span class="nd"&gt;@log_fn&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This is the same as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;sum_up_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;There are virtually no limits on the amount of decorators decorating
a function (beside the stack limit) however you may want to keep that
number low for code readability.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="decorators-with-arguments-1"&gt;
&lt;span id="decorators-with-arguments"&gt;&lt;/span&gt;&lt;h2&gt;Decorators with arguments&lt;/h2&gt;
&lt;p&gt;So far we've been exploring simple decorators and their usage,
which is just the tip of the iceberg. For example, decorators
accept arguments the same way as any ordinary function does.
This makes them even more powerful and versatile.
But before jumping there, let's take a look at an important
technique which always follows decorators source.&lt;/p&gt;
&lt;div class="section" id="wrapping-functions-properly-1"&gt;
&lt;span id="wrapping-functions-properly"&gt;&lt;/span&gt;&lt;h3&gt;Wrapping functions properly&lt;/h3&gt;
&lt;p&gt;Let's call &lt;tt class="docutils literal"&gt;sum_up_to()&lt;/tt&gt; from the last example, where it
has been decorated with both &lt;tt class="docutils literal"&gt;timeit&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;log_fn&lt;/tt&gt;.
The printed result may look a little bit unexpected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10e6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="go"&gt;sum_up_to( 10000000,  ) =&amp;gt; 49999995000000&lt;/span&gt;
&lt;span class="go"&gt;wrapper() execution time: 0.4475877285003662 s.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Did you notice that the name of the function in the output
is not &lt;tt class="docutils literal"&gt;sum_up_to&lt;/tt&gt; but &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt;? This behaviour is not a bug.
Take a minute to find out why this happens.&lt;/p&gt;
&lt;p&gt;Let's unwrap the decorator call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# Python unwraps the decorator call into this:&lt;/span&gt;
&lt;span class="n"&gt;sum_up_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# First, log_fn(sum_up_to) is executed, which returns&lt;/span&gt;
&lt;span class="c1"&gt;# log_fn&amp;#39;s internal `wrapper` function:&lt;/span&gt;
&lt;span class="n"&gt;log_fn_wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Hence, `timeit` is called with `log_argument_wrapper`&lt;/span&gt;
&lt;span class="c1"&gt;# as an argument:&lt;/span&gt;
&lt;span class="n"&gt;sum_up_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_fn_wrapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The problem is that &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt; does not mimic the original function. To overcome this, attributes like &lt;tt class="docutils literal"&gt;__name__&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;__doc__&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;__module__&lt;/tt&gt; etc. from the original function should be copied to &lt;tt class="docutils literal"&gt;wrapper&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;
    &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__doc__&lt;/span&gt;
    &lt;span class="n"&gt;wrapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__module__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__module__&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Though this code works fine, it means that one would have to write the same attributes copying routine in every decorator. Sounds familiar? Indeed, why not write yet another decorator, which does the attributes copying? Guess what, the standard library already contains a function &lt;tt class="docutils literal"&gt;wraps()&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; which gracefully handles this issue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;functools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;log_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@timeit&lt;/span&gt;
&lt;span class="nd"&gt;@log_fn&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&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; &lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10e6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;49999995000000&lt;/span&gt;
&lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.9093782901763916&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Wonderful! Now &lt;tt class="docutils literal"&gt;timeit()&lt;/tt&gt; prints the name of the decorated function.
One thing you have probably noticed about &lt;tt class="docutils literal"&gt;wraps&lt;/tt&gt; is that it actually accepts an argument! Now that you know how-to wrap a decorator properly, let's find out how to pass arguments to decorators.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="decorators-and-arguments-1"&gt;
&lt;span id="decorators-and-arguments"&gt;&lt;/span&gt;&lt;h3&gt;Decorators and arguments&lt;/h3&gt;
&lt;p&gt;Decorators are functions, so they accept arguments the same way as any other function does.
For example, let's update the &lt;tt class="docutils literal"&gt;timeit&lt;/tt&gt; decorator to log the function calls
which take more than N seconds to complete:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@timeit&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="c1"&gt;# 100 milliseconds&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;How to implement such a decorator? Remember that by definition,
a decorator accepts a single argument only (i.e. the decorated function),
thus accepting an integer in the example above breaks the rules.
The trick is that it is not &lt;tt class="docutils literal"&gt;timeit&lt;/tt&gt; which decorates &lt;tt class="docutils literal"&gt;sum_up_to&lt;/tt&gt;,
but rather the result of &lt;tt class="docutils literal"&gt;timeit(0.1)&lt;/tt&gt; call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# wrap properly&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;What happens when a function e.g. &lt;tt class="docutils literal"&gt;sum_up_to&lt;/tt&gt; is decorated as &lt;tt class="docutils literal"&gt;&amp;#64;timeit(0.1)&lt;/tt&gt;?
First, Python calls &lt;tt class="docutils literal"&gt;timeit(0.1)&lt;/tt&gt; which &lt;strong&gt;builds&lt;/strong&gt; a decorator and returns it.
Then, Python decorates &lt;tt class="docutils literal"&gt;sum_up_to&lt;/tt&gt; with the obtained decorator. It all can be
decomposed as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="n"&gt;timeit_decorator_100ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timeit&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="nd"&gt;@timeit_decorator_100ms&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;There are no limits on decorators' arguments design. For example, a
version of &lt;tt class="docutils literal"&gt;timeit&lt;/tt&gt; which accepts two arguments: a limit and a printer
function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;logging&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;printer_fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="o"&gt;...&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;printer_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;() execution time: &lt;/span&gt;&lt;span class="si"&gt;{:.2}&lt;/span&gt;&lt;span class="s1"&gt; s.&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff&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;ret&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;decorator&lt;/span&gt;

&lt;span class="nd"&gt;@timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;printer_fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="class-as-a-decorator"&gt;
&lt;h3&gt;Class as a decorator&lt;/h3&gt;
&lt;p&gt;Python allows taking the idea of decorators with arguments even further.
Classes can be effectively used to reduce the amount of nested functions
and to improve the code of  complex decorators.&lt;/p&gt;
&lt;p&gt;There is no magic in using classes: first, Python creates an object
from a class and then calls it (i.e. invokes object's &lt;tt class="docutils literal"&gt;__call__()&lt;/tt&gt; method)
to decorate a function.&lt;/p&gt;
&lt;p&gt;Let's rewrite &lt;tt class="docutils literal"&gt;timeit(limit, printer_fn)&lt;/tt&gt; as a class. The arguments are
passed through &lt;tt class="docutils literal"&gt;__init__()&lt;/tt&gt; method and are stored as class attributes.
The &lt;tt class="docutils literal"&gt;__call__()&lt;/tt&gt; method returns a wrapped function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;timeit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;printer_fn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;limit&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printer_fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;printer_fn&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__call__&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;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &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;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;tick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&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;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&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;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&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;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tick&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printer_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;() execution time: &lt;/span&gt;&lt;span class="si"&gt;{:.2}&lt;/span&gt;&lt;span class="s1"&gt; s.&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diff&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;ret&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;

&lt;span class="nd"&gt;@timeit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;


  &lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;10e6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sum_up_to&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="function-decorators-vs-class-decorators"&gt;
&lt;span id="function-vs-class"&gt;&lt;/span&gt;&lt;h3&gt;Function-decorators vs. class-decorators&lt;/h3&gt;
&lt;p&gt;&lt;a class="reference external" href="http://python.org/dev/peps/pep-0020/"&gt;PEP-20&lt;/a&gt; states that&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.&lt;/blockquote&gt;
&lt;p&gt;Unless writing decorators on a regular basis, one would wonder, what
are the benefits of using function-decorators vs. class-decorators and vice-verse?
Function-decorators are&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Simple and clear when no decorator arguments are required.&lt;/li&gt;
&lt;li&gt;Even simpler when a decorator returns the original function, not a wrapper.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However class decorators&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Allow better decomposition of complex decorators.&lt;/li&gt;
&lt;li&gt;Provide clearer syntax to store &lt;strong&gt;state&lt;/strong&gt; of a decorator both local and global.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The choice whether to write a decorator as a function or a class always depends
on the case or personal preferences. As a rule of thumb -
if the logic behind the decorator is complex, then go on with a class.
Otherwise, pick a function approach.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="decorating-methods-1"&gt;
&lt;span id="decorating-methods"&gt;&lt;/span&gt;&lt;h2&gt;Decorating methods&lt;/h2&gt;
&lt;p&gt;The syntax of decorating class methods is similar to decorating functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="nd"&gt;@log_fn&lt;/span&gt;
    &lt;span class="nd"&gt;@timeit&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&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;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;You are most probably familiar with the built-in &lt;tt class="docutils literal"&gt;property&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-3"&gt;[6]&lt;/a&gt;, &lt;tt class="docutils literal"&gt;classmethod&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-7" id="footnote-reference-4"&gt;[7]&lt;/a&gt; and &lt;tt class="docutils literal"&gt;staticmethod&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-5"&gt;[1]&lt;/a&gt;
decorators. For example here a calculator's epsilon is a read-only property:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;_eps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.00001&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;eps&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="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_eps&lt;/span&gt;

&lt;span class="n"&gt;calc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Calculator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.00001&lt;/span&gt;

&lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ne"&gt;AttributeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;t set attribute&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="section" id="self-and-method-decorators"&gt;
&lt;h3&gt;Self and method decorators&lt;/h3&gt;
&lt;p&gt;Method decorators may have an explicit access to self. Consider this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;decorator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# WARNING, do not do this!&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wrapper&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="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;m&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="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;wrapper&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;However this is a dangerous construction. A generic decorator &lt;strong&gt;should not&lt;/strong&gt; access &lt;tt class="docutils literal"&gt;self&lt;/tt&gt;
argument of the decorator method. As a matter of fact, a generic decorator &lt;strong&gt;should not&lt;/strong&gt; know
anything about the decorated callable, whether it is a function, a method, or a
wrapper returned by another decorator. Otherwise it breaks the universal protocol
and for example makes impossible chaining the decorators in an arbitrary order.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="decorating-classes-1"&gt;
&lt;span id="decorating-classes"&gt;&lt;/span&gt;&lt;h2&gt;Decorating classes&lt;/h2&gt;
&lt;p&gt;When function decorators were originally debated for inclusion in Python 2.4, class decorators were seen as obscure and unnecessary thanks to metaclasses. After several years' experience with the Python 2.4.x series of releases and an increasing familiarity with function decorators and their uses, Guido van Rossum aka BDFL and the community re-evaluated class decorators and recommended their inclusion in Python 3.0 &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-6"&gt;[3]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The use cases however are not that obvious &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-7"&gt;[4]&lt;/a&gt;. That is because
which could be done via class decorators, could be as well done
via good old metaclasses. It seems that &lt;em&gt;the&lt;/em&gt; usage case is
registering a class in any kind of chain like a plugins
system.&lt;/p&gt;
&lt;p&gt;A hint of such usage, is the standard library's &lt;tt class="docutils literal"&gt;unittest.skip*&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-8"&gt;[5]&lt;/a&gt; functions,
for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@unittest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skipUnless&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LOGGING_ENABLED&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;LoggingTest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_smoke&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="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This test will be executed, only if a &lt;cite&gt;Logging&lt;/cite&gt; feature is enabled
in application's settings.&lt;/p&gt;
&lt;p&gt;Consider another example: a media player application which supports plugins:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;player.plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AACPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AACPlugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# This plugin is still experimental and is not&lt;/span&gt;
&lt;span class="c1"&gt;# registered in Player&amp;#39;s plugins system&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AACExperimentalPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Wouldn't it be easier to write&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nd"&gt;@register&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AACPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;?&lt;/p&gt;
&lt;p&gt;Also, why not automatically register the plugins which inherit from &lt;tt class="docutils literal"&gt;Plugin&lt;/tt&gt;
class? Gotcha! What if you &lt;strong&gt;do not&lt;/strong&gt; want to register the plugin yet, whether
it is experimental, or incomplete, or for any other reason? That's where
decorators allow expressing developer's intention in a clear and non-ambiguous
manner.&lt;/p&gt;
&lt;div class="section" id="example-registering-a-plugin"&gt;
&lt;h3&gt;Example: Registering a plugin&lt;/h3&gt;
&lt;p&gt;Let's consider the case described above : A media player application has a plugins system
which extend its basic capabilities. A &lt;tt class="docutils literal"&gt;player.plugins.register()&lt;/tt&gt; call is used
to register an arbitrary class as a plugin. An API user should not care, about
&lt;tt class="docutils literal"&gt;register()&lt;/tt&gt; 's internals, however in this case, &lt;tt class="docutils literal"&gt;register()&lt;/tt&gt; simply validates
the classes and stores them in a global &lt;tt class="docutils literal"&gt;_plugins&lt;/tt&gt; list:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt; &lt;span class="c1"&gt;# --- in player/plugins.py --- #&lt;/span&gt;

 &lt;span class="n"&gt;_plugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

 &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="sd"&gt;&amp;#39;&amp;#39;&amp;#39;Plugin base class&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;


 &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
         &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cannot register a class as a Plugin: wrong type &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&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="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

     &lt;span class="n"&gt;_plugins&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&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="bp"&gt;cls&lt;/span&gt;


&lt;span class="c1"&gt;# --- usage in 3d-party module --- #&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;player.plugins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;

&lt;span class="nd"&gt;@register&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AACPlugin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Plugin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="finale"&gt;
&lt;h2&gt;Finale&lt;/h2&gt;
&lt;p&gt;This is it! Thank you for reading, I hope you enjoyed!
Please leave a comment, ask a question, or just share this article with
anyone who is still lost in the world of Python decorators :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[1]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#footnote-reference-1"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#footnote-reference-5"&gt;2&lt;/a&gt;)&lt;/em&gt; &lt;a class="reference external" href="https://docs.python.org/3/library/functions.html?highlight=staticmethod#staticmethod"&gt;staticmethod&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://docs.python.org/3/library/functools.html?highlight=wraps#functools.wraps"&gt;&amp;#64;functools.wraps&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-6"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-3129/"&gt;PEP 3129&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-7"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://softwareengineering.stackexchange.com/questions/334195/class-decorators-in-python-practical-use-cases"&gt;Class decorators in Python: practical use cases&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-8"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://docs.python.org/2/library/unittest.html#unittest.skip"&gt;unittest.skip&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://docs.python.org/3/library/functions.html?#property"&gt;property&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-7" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[7]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://docs.python.org/3/library/functions.html?#classmethod"&gt;classmethod&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Python"/><category term="programming"/></entry><entry><title>My story of caffeine withdrawal</title><link href="https://zaurnasibov.com/posts/2015/05/31/caffeine_withdrawal.html" rel="alternate"/><published>2015-05-31T12:00:00+03:00</published><updated>2015-05-31T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2015-05-31:/posts/2015/05/31/caffeine_withdrawal.html</id><summary type="html">&lt;p class="first last"&gt;After getting hooked on coffee, I decided to stop drinking
caffeinated drinks. This is a story of my detoxification.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="it-all-started"&gt;
&lt;h2&gt;It all started...&lt;/h2&gt;
&lt;p&gt;It all started long before I turned two years old. I started drinking tea!
Properly saying, I drank whatever was in the bottle and no one asked
my opinion. Drinking tea is an Azeri tradition, you will be offered tea
everywhere, at any meeting, gathering or reception, party or mourning and
many other occasions. Speaking of, that is not a &lt;em&gt;tea from a teabag&lt;/em&gt;, no sir!
It is a properly brewed tea almost at a boiling point of water.
The taste is great and is fully-flavoured.&lt;/p&gt;
&lt;img alt="Tea set, Lahic, Azerbaijan | photographer: Orkhan Gurbanzada | from photodom.com" class="align-center" src="https://zaurnasibov.com/articles/2015_05_31_caffeine_withdrawal/caffeine_withdrawal_azeri_tea.jpg" /&gt;
&lt;p&gt;I have been drinking coffee since university. Tea was not enough to
sustain my brain during the nights before exams (how stupid that sounds today!).
Then, I turned to energy drinks. What a perfect example of how
cheap caffeine tablets are sold in a form of overpriced liquid!&lt;/p&gt;
&lt;p&gt;Nevertheless, tea was my favourite in the family of hot drinks. I drank
coffee occasionally and had an energy drink or two, couple times
a month.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="getting-hooked-up"&gt;
&lt;h2&gt;Getting hooked up&lt;/h2&gt;
&lt;p&gt;Lately I noticed obtaining a new &amp;quot;drinking coffee at work&amp;quot; habbit.
I had a cup of coffee in the morning right after logging in.
I had another cup right after lunch and usually the third cup
just before leaving home.&lt;/p&gt;
&lt;img alt="A cup of coffee" class="align-center" src="https://zaurnasibov.com/articles/2015_05_31_caffeine_withdrawal/caffeine_withdrawal_coffee.jpg" /&gt;
&lt;p&gt;The side effects came out rather quickly: Drinking coffee for
productivity turned into drinking to feel normal. I could not
start a day without coffee anymore. I started getting sleepy
in the evenings, as I did not drink any coffee at home.&lt;/p&gt;
&lt;p&gt;Finally, I decided to stop drinking anything with caffeine
in it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="detox"&gt;
&lt;h2&gt;Detox&lt;/h2&gt;
&lt;p&gt;There are great caffeine detoxing advises on
&lt;a class="reference external" href="http://caffeineinformer.com"&gt;caffeineinformer.com&lt;/a&gt;.
I chose the &lt;cite&gt;The Cold Turkey Method&lt;/cite&gt; i.e. ceased
consuming caffeine at all. In a retrospective, that was a
naughty move. The detox process went as follows:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Day I&lt;/strong&gt;: Running nose and irritating headache. Hard to
think and hard to move. I had to take a doze of ibuprofen
painkiller to ease the symptoms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Day II&lt;/strong&gt;: Headache and running nose continues. Severe
muscles pain started to build around back of the neck.
Another single doze of ibuprofen. I'd take paracetamol instead,
but most of those painkillers are mixed with caffeine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Day III&lt;/strong&gt;: Headache is not as bad, muscles are still
suffering. No painkillers today.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Day IV&lt;/strong&gt;: Headache is almost over. Nose is lightly running.
Muscles pain starting to fade.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Day V&lt;/strong&gt;: Feeling much better. Headache is completely gone,
I had to do some exercise to completely get rid of muscles
pain, or rather turn it into a rewarding post-exercise
itch.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt="Inside caffeine withdrawal" class="align-center" src="https://zaurnasibov.com/articles/2015_05_31_caffeine_withdrawal/caffeine_withdrawal_inside.jpg" /&gt;
&lt;p&gt;That was it! My body got back to normal, I did not need
coffee or tea to wake up or feel good. My brain was
completely cured from the caffeine addiction.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="afterwards"&gt;
&lt;h2&gt;Afterwards&lt;/h2&gt;
&lt;p&gt;That was not the end of the it yet! I opted to drink only water
for three more weeks. It was almost summer, the weather was warm
thus, no need to warm up by drinking something hot. These weeks
went fine. I only noticed consuming more water than before.
Eventually I started drinking tea again. Coffee was left as a
&amp;quot;brain doping&amp;quot; which I'm willing to take only when it is really
required.&lt;/p&gt;
&lt;p&gt;Do you have any withdrawal experience? I'd be glad to hear your
story! If you want to try (though I'd hardly recommend it :)
check &lt;a class="reference external" href="http://caffeineinformer.com"&gt;caffeineinformer.com&lt;/a&gt;
for great advises and more valuable information on human body
and caffeine interaction.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Life"/><category term="Caffeine"/></entry><entry><title>Python nightmares: Implicit this</title><link href="https://zaurnasibov.com/posts/2015/05/11/python_nightmares_implicit_this.html" rel="alternate"/><published>2015-05-11T22:00:00+03:00</published><updated>2015-05-11T22:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2015-05-11:/posts/2015/05/11/python_nightmares_implicit_this.html</id><summary type="html">&lt;p class="first last"&gt;I met a lot of Python beginners who complained about &lt;tt class="docutils literal"&gt;this&lt;/tt&gt;
keyword not implicitly available in class methods. After all,
why pass &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; explicitly?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;My first line of defense against such heresy is
&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0020/"&gt;PEP 20 - The Zen of Python&lt;/a&gt;,
which states that &lt;em&gt;Explicit is better than implicit.&lt;/em&gt;
Next comes the fact that Python class methods are in functions, bound
to a class instance via descriptor protocol.
If this sounds complex, I strongly encourage you to check the great
&lt;a class="reference external" href="https://docs.python.org/3/howto/descriptor.html"&gt;Descriptor HowTo Guide&lt;/a&gt;
from the official documentation.
In general, passing function arguments through magic variables is awful
(think of Perl with its &lt;tt class="docutils literal"&gt;$&lt;/tt&gt;)!
Why pass an object through a magical &lt;tt class="docutils literal"&gt;this&lt;/tt&gt;?&lt;/p&gt;
&lt;p&gt;Finally, it is possible to hide &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; and pass &lt;tt class="docutils literal"&gt;this&lt;/tt&gt; implicitly.
The easiest way is to do it by decorating a method:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# NOTE: all code examples are done in Python 3&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add_this&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wrapped&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="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;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__globals__&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;this&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&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;wrapped&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alex&amp;#39;&lt;/span&gt;

    &lt;span class="nd"&gt;@add_this&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt; says: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Can you believe it? There is no `self` here!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;Alex says: Can you believe it? There is no `self` here!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;As you can see, there is no &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; argument in &lt;tt class="docutils literal"&gt;say()&lt;/tt&gt; method,
but there is an implicit &lt;tt class="docutils literal"&gt;this&lt;/tt&gt;! What happens in &lt;tt class="docutils literal"&gt;add_this()&lt;/tt&gt;
decorator is that we modify function's &lt;tt class="docutils literal"&gt;__globals__&lt;/tt&gt; dictionary,
adding &lt;tt class="docutils literal"&gt;this&lt;/tt&gt; variable with value of &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; to the scope.
Recall that &lt;tt class="docutils literal"&gt;__globals__&lt;/tt&gt; is&lt;/p&gt;
&lt;blockquote&gt;
A reference to the dictionary that holds the function’s
global variables — the global namespace of the module in
which the function was defined &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/blockquote&gt;
&lt;p&gt;Thus, modifying it, we also modify the global scope of the current
module. This is certainly not the way to go, but is enough for
simple demonstration.&lt;/p&gt;
&lt;p&gt;If that is not crazy enough, let's write a metaclass which takes
care of decorating methods automatically:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;types&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AddThisMeta&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="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classdict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;new_classdict&lt;/span&gt; &lt;span class="o"&gt;=&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="n"&gt;add_this&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FunctionType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;classdict&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;new_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__new__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_classdict&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;new_class&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;D&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;AddThisMeta&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Daniel&amp;#39;&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt; says: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;phrase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s2"&gt; runs away :)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;say&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;And now, there is only AddThisMeta!&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="go"&gt;Daniel says: And now, there is only AddThisMeta!&lt;/span&gt;
&lt;span class="go"&gt;Daniel runs away :)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here, the metaclass does the same job we did above: it wraps
all the methods which have a plain &lt;tt class="docutils literal"&gt;function&lt;/tt&gt; type in class dictionary
via &lt;tt class="docutils literal"&gt;add_this()&lt;/tt&gt; decorator.&lt;/p&gt;
&lt;p&gt;As you can see, it is not hard at all to introduce an implicit &lt;tt class="docutils literal"&gt;this&lt;/tt&gt;
in your code. But please, for all the good we have in Python,
&lt;strong&gt;don't even think about doing it!&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://docs.python.org/3/reference/datamodel.html"&gt;https://docs.python.org/3/reference/datamodel.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Python"/><category term="programming"/></entry><entry><title>A micro Lisp interpreter experiment</title><link href="https://zaurnasibov.com/posts/2014/06/21/a_micro_lisp_interpreter_experiment.html" rel="alternate"/><published>2014-06-21T12:00:00+03:00</published><updated>2014-06-21T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2014-06-21:/posts/2014/06/21/a_micro_lisp_interpreter_experiment.html</id><summary type="html">&lt;p class="first last"&gt;While reading the &lt;cite&gt;Binary trees&lt;/cite&gt; chapter from &lt;a class="reference external" href="http://www.piexposed.com"&gt;Programming Interviews Exposed&lt;/a&gt; by John Mongan et al. I started thinking of alternative recursion examples which do not involve sorting, generating Fibonacci sequence, binary tree traversal and similar tasks. Lisp! Lisp is inseparable from recursion and Lisp interpreter would be a good case to demonstrate what recursion is and how it can be used efficiently. What would be a minimal simplified Lisp interpreter written in Python? Surprisingly, I managed to do it just in 6 lines of Python code! And this is not just because of Python being a wonderful language, but because of Lisp being such a beautiful and simple concept.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Let's define the language grammar and evaluation forms:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;list := (item0, item1, ...)
item := list | atom
atom := stringliteral|numliteral
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The evaluation rules are similar to any Lisp: the first atom is a function,
the rest - are the arguments:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;fn = list[0]
args = list[1:]
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Notice that a list is written in a form of Python tuple. This is in a way
a cheat which allows decreasing the interpreter's code dramatically (i.e.
Python does the lexical and syntax analysis).
Also note that the interpreter does not include any built-in operators,
functions or special forms. They can all be created to extend the language
separately.&lt;/p&gt;
&lt;p&gt;Let's write some examples before jumping to the code of the interpreter and
its extension functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;quote,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; &amp;gt;&amp;gt;&amp;gt; (1, 2, 3)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;plus,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;; &amp;gt;&amp;gt;&amp;gt; 6&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inc,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;; &amp;gt;&amp;gt;&amp;gt; 11&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Allright, enough sentimental talk, let's get to the interpreter!&lt;/p&gt;
&lt;div class="section" id="the-micro-lisp-interpreter"&gt;
&lt;h2&gt;The micro Lisp interpreter&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_or_atom&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_or_atom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fn_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;list_or_atom&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;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fn_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&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;list_or_atom&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;That is it! Here is how it works:
First, we check whether the input is a list (Python tuple) or an atom.
In case if it is an atom we return it immediately. Thus, &lt;tt class="docutils literal"&gt;eval(1)&lt;/tt&gt;
returns &lt;tt class="docutils literal"&gt;1&lt;/tt&gt;. If the argument is a tuple, we extract a function
as its first element, and supply the rest elements as function arguments,
recursively evaluating them in-place.
Let's write various functions to extend this basic interpreter.&lt;/p&gt;
&lt;div class="section" id="quote"&gt;
&lt;h3&gt;quote&lt;/h3&gt;
&lt;p&gt;Quoting is used to separate expressions from data in Lisp.
For example, in Emacs-Lisp it is &lt;tt class="docutils literal"&gt;(quote 1 2 3)&lt;/tt&gt;, which is usually
written via quotation prefix as &lt;tt class="docutils literal"&gt;'(1 2 3)&lt;/tt&gt;. Without quotation,
Lisp will interprete this as a function call, where the first symbol
(&lt;tt class="docutils literal"&gt;1&lt;/tt&gt;) is a function name and &lt;tt class="docutils literal"&gt;2 3&lt;/tt&gt; - are function arguments.
Because we are limited by Python syntax, it is impossible to introduce
Lisp-alike special quote forms, i.e. &lt;tt class="docutils literal"&gt;'(1 2 3)&lt;/tt&gt;. Thus, &lt;tt class="docutils literal"&gt;quote&lt;/tt&gt;
should be written as a function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;quote&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="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Returns a list without evaluating it.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;tuple&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="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Please be aware&lt;/strong&gt;, that this is still a rudimentary quotation, which
does not work correctly for quoted sub-lists. For example, in any
Lisp the following evaluation takes places:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nv"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;quote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;However it evaluates to the following code in this mini-interpreter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="plus"&gt;
&lt;h3&gt;plus&lt;/h3&gt;
&lt;p&gt;Let's write a mathematical function. Usually the &lt;tt class="docutils literal"&gt;+&lt;/tt&gt; operator is used
in various Lisp dialects for summing, but we are still limited with
Python's syntax, which would not allow writing &lt;tt class="docutils literal"&gt;(+, 2, 3)&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;plus&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="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Sums up the input arguments.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;sum&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="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And here come two nice examples with recursion:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;

&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&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="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="apply"&gt;
&lt;h3&gt;apply&lt;/h3&gt;
&lt;p&gt;What happens if you try to plus a list, like &lt;tt class="docutils literal"&gt;(plus, (quote, 1, 2, 3))&lt;/tt&gt;?
The interpreter will crash because it will end up calling Python's
&lt;tt class="docutils literal"&gt;sum&lt;/tt&gt; as &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;sum([(1,&lt;/span&gt; 2, 3), ])&lt;/tt&gt;. A typical Lisp dialect deals with this
problem via &lt;tt class="docutils literal"&gt;apply&lt;/tt&gt; function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;apply&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="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Applies a function to a list of arguments.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fn&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;fn_args&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fn_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="map-and-inc"&gt;
&lt;h3&gt;map and inc&lt;/h3&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;map&lt;/tt&gt; function takes another function and a list as input, applies
the function to each element of this list and returns the results in a new
list. For example: &lt;tt class="docutils literal"&gt;(map, inc, (quote, 1, 2, 3))&lt;/tt&gt; returns &lt;tt class="docutils literal"&gt;(2, 3, 4)&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Here, &lt;tt class="docutils literal"&gt;inc&lt;/tt&gt; - is a simple function which returns the value of it's
argument + 1. For example, &lt;tt class="docutils literal"&gt;(inc, 10)&lt;/tt&gt; returns &lt;tt class="docutils literal"&gt;11&lt;/tt&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;map&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="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Apply the function to each element of the list and return&lt;/span&gt;
&lt;span class="sd"&gt;       the results in a new list.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;fn&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;fn_args&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fn_args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Increases the argument by 1.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="lambdas"&gt;
&lt;h3&gt;lambdas&lt;/h3&gt;
&lt;p&gt;I was looking for a nice way of writing lambdas without modifying
the base interpreter. Unfortunately using the Python lambdas directly
would require putting an explicit &lt;tt class="docutils literal"&gt;eval()&lt;/tt&gt; in the lambda body, e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Would not work because &lt;tt class="docutils literal"&gt;(plus, x, 1)&lt;/tt&gt; is never evaluated. To make
this work we have to write it as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;which destroys the consistency of the syntax. Ruby code blocks would
be indeed helpful here :)&lt;/p&gt;
&lt;p&gt;I will stop extending the interpreter now. As you see the interpreter
is not complete and it is quite primitive. But the aim of this article
is to show another way of demonstrating and teaching recursion in Python
through the beauty of Lisp :) I hope you enjoyed it!
Looking forward for your comments and solutions!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Python"/><category term="Lisp"/><category term="programming"/></entry><entry><title>ECCO online</title><link href="https://zaurnasibov.com/posts/2014/02/01/ecco_online.html" rel="alternate"/><published>2014-02-01T12:00:00+02:00</published><updated>2014-02-01T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2014-02-01:/posts/2014/02/01/ecco_online.html</id><summary type="html">&lt;p class="first last"&gt;Ah, magnificent Finnish winter! First, it was jumping around zero (Celsius of course), so that people had to deal with slippery roads and pavement, then it dropped to -25, so that people put on layers of clothes. Then a snowstorm hit Finland, and it was above -10 again, with mountains of snow. There is an important part of the wardrobe that helps dealing with all these weather conditions: the &lt;strong&gt;shoes&lt;/strong&gt;.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="why"&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;My old boots' life was coming to an end. They are 5 years old and
have served me very well. Considering the winter in Finland, investing
into warm, water-proof and well-breathing winter boots with a tough
iced surface grip is a must.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="when"&gt;
&lt;h2&gt;When?&lt;/h2&gt;
&lt;p&gt;Christmas sales? After New year discounts? Nonsense!&lt;/p&gt;
&lt;p&gt;I believe that the best time to buy cloths is a time close to the end
of a season. It is hard to call the end of January an &amp;quot;end of the season&amp;quot;,
nevertheless you may find that huge discounts on various seasonal cloths
have already started. Certainly, there are even bigger discounts after
the season ends - but then, the choice is extremely limited.
If you get lucky - the discount can be dramatic. For example: we bought
new roller skates for my wife, with a 75% discount in September. It
was the last pair of the required size :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="where"&gt;
&lt;h2&gt;Where?&lt;/h2&gt;
&lt;p&gt;I consider ordering shoes online a risky business. Time is money and it
takes time for the shoes to arrive and if they don't fit - it takes
time for the backward process.
On the other hand, online stores have better price offers and discounts.
The best ones include a &amp;quot;send it back&amp;quot; post tag into the original package
which can be used to send the shoes back to the shop if they don't fit.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="who"&gt;
&lt;h2&gt;Who?&lt;/h2&gt;
&lt;p&gt;Extreme Nordic weather requires solid Nordic shoes to deal with it.
Some of you have probably heard of Danish &lt;a class="reference external" href="http://ecco.com/"&gt;ECCO&lt;/a&gt;. I've been buying ECCO shoes,
sandals, pumps, boots, trainers for years. Finally, I've got so assured
with them, that I ordered new winter boots online. They came with a nice
40% discount, which decreased the price from 225 to 135 EUR. Now, 135 EUR
may seem quite a price, but hey, if you expect at least 3-4 years of
service, it drops to ~39 EUR/year. Isn't that a bargain?! Hell, my &lt;em&gt;monthly&lt;/em&gt;
Internet bill is about that amount of money. So, here it is ECCO Roxton:&lt;/p&gt;
&lt;img alt="ecco roxton" class="align-center" src="https://zaurnasibov.com/articles/2014_02_01_ecco_online/roxton.jpg" /&gt;
&lt;p&gt;The official ad says:&lt;/p&gt;
&lt;p&gt;Warm up to Winter, in these sheepskin-lined 100% waterproof boots.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Lace up, high-cut boot style with metal D-rings and speed lacing system&lt;/li&gt;
&lt;li&gt;Designed for premium comfort, warmth and insulation&lt;/li&gt;
&lt;li&gt;Uppers of oiled nubuck, suede and textile - for durability and a comfortable fit&lt;/li&gt;
&lt;li&gt;Warm lining of lambskin and wool provides superior, natural insulation&lt;/li&gt;
&lt;li&gt;Gore-tex® lining provides a 100% waterproof guarantee, ensuring dry feet at all times&lt;/li&gt;
&lt;li&gt;Direct-injected sole provides lightweight durability, flexibility and won't weigh you down&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It took me a week to wear them in. The boots are a bit heavier than my
old ones and have a thicker sole. After a week I can sincerely say, that
these are the best winter boots I owned ever! Thank you, ECCO!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="life"/><category term="shoes"/><category term="ECCO"/></entry><entry><title>Kidomi - a JSON-based templating library</title><link href="https://zaurnasibov.com/posts/2014/01/05/kidomi.html" rel="alternate"/><published>2014-01-05T12:00:00+02:00</published><updated>2014-01-05T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2014-01-05:/posts/2014/01/05/kidomi.html</id><summary type="html">&lt;p class="first last"&gt;&lt;strong&gt;kidomi&lt;/strong&gt; - is a simple yet powerful javascript templating library which converts JSON input into a certain DOMNode output. Kidomi was written after I have had a chance to try the &lt;a class="reference external" href="https://github.com/Prismatic/dommy"&gt;dommy&lt;/a&gt; ClojureScript library in production.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Certainly, ClojureScript plays a major role in why the templating syntax seems so natural and pleasant, e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:span&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:style&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#aaa&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="ss"&gt;:text-decoration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;line-through&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello world!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But with JavaScript arrays and objects, there is a way to create something similar&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;kidomi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;span&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;,
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;style&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;color&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;#&lt;/span&gt;&lt;span class="nv"&gt;aaa&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;,
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;text-decoration&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;line-through&lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;,
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello world!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Which outputs a HTMLElement with the following nested structure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;color:#aaa; text-decoration:line-through&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  hello world!
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Kidomi is written in CoffeeScript. It is covered by unit tests via
&lt;a class="reference external" href="http://qunitjs.com/"&gt;QUnit&lt;/a&gt; and can be used by a &lt;a class="reference external" href="https://developers.google.com/closure/compiler"&gt;Google Closure compiler&lt;/a&gt;
in an &lt;em&gt;ADVANCED_MODE&lt;/em&gt; compilation or separately (e.g. to produce a minified output).&lt;/p&gt;
&lt;div class="section" id="usage"&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;kidomi(data)&lt;/tt&gt; function returns a HTMLNode constructed from a data,
for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kidomi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div#main.content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;color&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;blue&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Select file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;form&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;inputName&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;action&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;getform.php&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;method&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;get&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Username: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;input&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;submit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Submit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}]]])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The generated HTML element is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;color: blue;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Select file&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;inputName&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;getform.php&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;get&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    Username:
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;submit&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Submit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="syntax"&gt;
&lt;h2&gt;Syntax&lt;/h2&gt;
&lt;p&gt;The general syntax of kidomi is: &lt;tt class="docutils literal"&gt;node = kidomi(parsableObject)&lt;/tt&gt;.
Here, node is a HTMLElement or in a more generic case a DOM node.&lt;/p&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;parsableObject&lt;/tt&gt; is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A string. The returned object is a Text node.&lt;/li&gt;
&lt;li&gt;A number. It is automatically converted to string and the returned object is a Text node.&lt;/li&gt;
&lt;li&gt;A node. The returned object is the same node.&lt;/li&gt;
&lt;li&gt;An array. This should be discussed a bit thoroughly:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The syntax of the parsableObject array is simple and very flexible.
It consists of at least one item, which is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;element#id.class1.class2.classN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here, &lt;tt class="docutils literal"&gt;id&lt;/tt&gt; - is the id attribute of the node, &lt;tt class="docutils literal"&gt;class1.class2.classN&lt;/tt&gt;
- CSS classes of the node, i.e. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;class=&amp;quot;class1&lt;/span&gt; class2 classN&amp;quot;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div#content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;div id=&amp;quot;content&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span#user.username&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;span id=&amp;quot;user&amp;quot; class=&amp;quot;username&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span.password&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;span class=&amp;quot;passwordd&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div.main.dialog&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;div class=&amp;quot;main dialog&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;// etc.&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The second item is either an attributes object, or a sub-&lt;tt class="docutils literal"&gt;parsableObject&lt;/tt&gt;.
The attributes object has the following syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;classN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;prop1&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;val1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;propN&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;valN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attribute1&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attributeN&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;valueN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class1 classN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;prop1:val1; propN:valN;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attribute1&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;value1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;attributeN&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;valueN&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;class&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;style&lt;/tt&gt; key-value pairs or strings are optional.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;class&lt;/tt&gt; key-value pair is an array or a string with CSS classes'
names applied to the node. It is appended to the classes found in the
first item of the &lt;tt class="docutils literal"&gt;parsableObject&lt;/tt&gt; array.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;style&lt;/tt&gt; key-value pair is an object or a string of CSS style
properties of the node.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;attributeX&lt;/tt&gt; key-value pairs are the attributes of the node.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;biglink&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;style&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;color&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;red&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;href&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://github.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

&lt;span class="c1"&gt;// &amp;lt;a href=&amp;quot;http://github.com&amp;quot; class=&amp;quot;biglink&amp;quot; style=&amp;quot;color:red;&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The rest of the array items are nested &lt;tt class="docutils literal"&gt;parsableObjects&lt;/tt&gt; or in a special
case - an array of arrays with &lt;tt class="docutils literal"&gt;parsableObjects&lt;/tt&gt;. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;// Nested elements&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span.name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Name: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span.lastname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Last name: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]]&lt;/span&gt;
&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt;   &amp;lt;div&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;     &amp;lt;div&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;       &amp;lt;span class=&amp;quot;name&amp;quot;&amp;gt;Name: &amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;       &amp;lt;span class=&amp;quot;lastname&amp;quot;&amp;gt;Last name: &amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;     &amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;   &amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;*/&lt;/span&gt;

&lt;span class="c1"&gt;// Expandable nested array&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Second&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Third&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]]&lt;/span&gt;
&lt;span class="cm"&gt;/*&lt;/span&gt;
&lt;span class="cm"&gt; &amp;lt;tr&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;   &amp;lt;td&amp;gt;First&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;   &amp;lt;td&amp;gt;Second&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;   &amp;lt;td&amp;gt;Third&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt; &amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;span class="cm"&gt;*/&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="building-and-testing"&gt;
&lt;h2&gt;Building and testing&lt;/h2&gt;
&lt;p&gt;You will need the following tools to build and test &lt;strong&gt;kidomi&lt;/strong&gt;:&lt;/p&gt;
&lt;ol class="arabic simple" start="0"&gt;
&lt;li&gt;GNU Make. This is used to run the &lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt; script.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://coffeescript.org"&gt;CoffeeScript&lt;/a&gt; compiler. This is enough to build the library.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://developers.google.com/closure/compiler/"&gt;Google Closure&lt;/a&gt; compiler. This is used to build the optimized
version of the library. The CoffeeScript code is written with the
Closure restrictions in mind.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://phantomjs.org/"&gt;PhantomJS&lt;/a&gt; is used to run the unit tests from a shell. You can as
well run them in a normal browser.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="advanced-usage"&gt;
&lt;h2&gt;Advanced usage&lt;/h2&gt;
&lt;div class="section" id="referencing-elements"&gt;
&lt;h3&gt;Referencing elements&lt;/h3&gt;
&lt;p&gt;One of the patterns where &lt;strong&gt;kidomi&lt;/strong&gt; might be especially handy is
when you have to create certain HTML elements before adding them in
a DOM structure. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kidomi&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;button&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hello world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;myDiv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kidomi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;div&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;span&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Click me:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myDiv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="list-comprehensions-in-coffeescript"&gt;
&lt;h3&gt;List comprehensions in CoffeeScript&lt;/h3&gt;
&lt;p&gt;List (array) comprehensions are very handy to use as the expandable
array elements, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;tr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]]]&lt;/span&gt;

&lt;span class="c1"&gt;# can be written as:&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;tr&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;td&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="CoffeeScript"/><category term="JavaScript"/><category term="programming"/></entry><entry><title>Is it a string?</title><link href="https://zaurnasibov.com/posts/2013/09/23/is_it_a_js_string.html" rel="alternate"/><published>2013-09-23T12:00:00+03:00</published><updated>2013-09-23T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2013-09-23:/posts/2013/09/23/is_it_a_js_string.html</id><summary type="html">&lt;p class="first last"&gt;How do you know if a Javascript variable is actually a string? There are several ways to answer this simple question.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;The most straightforward method of getting a variable type in javascript is
using the &lt;tt class="docutils literal"&gt;typeof&lt;/tt&gt; operator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;In a simple case&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;
&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;string&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But what do we know about javascript strings?&lt;/p&gt;
&lt;blockquote&gt;
The String global object is a constructor for strings, or a sequence of characters.
String literals take the forms &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;:&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;string text&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;string text&amp;quot;&lt;/span&gt;

&lt;span class="nx"&gt;Or&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sb"&gt;``&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="sb"&gt;``&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;directly&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now that is where it becomes a bit tricky:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;
&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;string&amp;#39;&lt;/span&gt;
&lt;span class="nx"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;0&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;so&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;object&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// it is not a &amp;#39;string&amp;#39; anymore!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And there is nothing wrong with the latter statement as because first of all &lt;tt class="docutils literal"&gt;so&lt;/tt&gt; is &lt;tt class="docutils literal"&gt;Object&lt;/tt&gt;
created via the &lt;tt class="docutils literal"&gt;new&lt;/tt&gt; operator. Fortunately the &lt;tt class="docutils literal"&gt;instanceof&lt;/tt&gt; operator can handle this scenario:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;so&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;instanceof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;!-- [:ref:`skip to the code &lt;thecode&gt;`] --&gt;
&lt;div class="section" id="the-code"&gt;
&lt;span id="thecode"&gt;&lt;/span&gt;&lt;h2&gt;The code&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;instanceof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;abc&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nx"&gt;isString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String"&gt;Mozilla Developer Network: String&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="JavaScript"/><category term="programming"/></entry><entry><title>Kaylee v0.3</title><link href="https://zaurnasibov.com/posts/2013/06/20/kaylee_0_3_released.html" rel="alternate"/><published>2013-06-20T12:00:00+03:00</published><updated>2013-06-20T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2013-06-20:/posts/2013/06/20/kaylee_0_3_released.html</id><summary type="html">&lt;p class="first last"&gt;Ladies and Gentlemen! I am proud to announce that Kaylee v0.3 has been finally released!&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="what-is-new-in-kaylee-0-3"&gt;
&lt;h2&gt;What is new in Kaylee 0.3&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#kaylee-environment-and-project-management-scripts"&gt;Kaylee environment and project management scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#built-in-debug-server"&gt;Built-in debug server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#native-werkzeug-framework-support"&gt;Native Werkzeug framework support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#demo-projects-repository"&gt;Demo projects repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#updated-unit-tests-and-massive-code-improvements"&gt;Updated unit tests and massive code improvements&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="kaylee-environment-and-project-management-scripts-1"&gt;
&lt;span id="kaylee-environment-and-project-management-scripts"&gt;&lt;/span&gt;&lt;h3&gt;Kaylee environment and project management scripts&lt;/h3&gt;
&lt;p&gt;This is the sweetest feature of Kaylee. Since the first release I felt
that although Kaylee may be an interesting project to an end user
(meaning a programmer), it has a pretty big fence which one has to jump
over to start using it. The tutorial was written in a plain and simple
language, yet a user had to create a &lt;cite&gt;Makefile&lt;/cite&gt;, learn about Kaylee's
recursive-make-based build system and perform some other simple but
inconvenient operations.&lt;/p&gt;
&lt;p&gt;The best way out of this were management scripts inspired by the &lt;em&gt;Django&lt;/em&gt;
framework. Now, a user can simply run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python kaylee-admin.py startenv myenv
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;to create a Kaylee development environment directory with a management
script inside it. The management script helps creating, building and testing
the projects, e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python klmanage.py startproject FastPI
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;- creates a &lt;tt class="docutils literal"&gt;fastpi&lt;/tt&gt; directory  with the project's server and client-side
skeletons.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="built-in-debug-server-1"&gt;
&lt;span id="built-in-debug-server"&gt;&lt;/span&gt;&lt;h3&gt;Built-in debug server&lt;/h3&gt;
&lt;p&gt;This feature is about testing and debugging your project without installing
a 3d party web server. Simply execute&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python klmanage.py run
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;after building the environment. The command starts a local web server, and
launches the first available application defined in the environment's
&lt;tt class="docutils literal"&gt;settings.py&lt;/tt&gt;. The application is then by-default accessible via
&lt;a class="reference external" href="http://127.0.0.1:5000"&gt;http://127.0.0.1:5000&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="native-werkzeug-framework-support-1"&gt;
&lt;span id="native-werkzeug-framework-support"&gt;&lt;/span&gt;&lt;h3&gt;Native Werkzeug framework support&lt;/h3&gt;
&lt;p&gt;Now you can easily integrate Kaylee into your &lt;a class="reference external" href="http://werkzeug.pocoo.org"&gt;Werkzeug&lt;/a&gt; -based web application
via native API. This is the third front-end framework which is supported by
Kaylee out-of-the box. The other two are &lt;a class="reference external" href="http://djangoproject.com"&gt;Django&lt;/a&gt; and &lt;a class="reference external" href="http://flask.pocoo.org"&gt;Flask&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="demo-projects-repository-1"&gt;
&lt;span id="demo-projects-repository"&gt;&lt;/span&gt;&lt;h3&gt;Demo projects repository&lt;/h3&gt;
&lt;p&gt;At last, all Kaylee demo projects, including the tutorial project are
gathered under a separate repository on github:
&lt;a class="reference external" href="https://github.com/BasicWolf/kaylee-demo-projects"&gt;https://github.com/BasicWolf/kaylee-demo-projects&lt;/a&gt;
In addition to the projects, the repository includes a special build script
which automatically creates a Kaylee demo environment, builds the projects
and starts the built-in debug server.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="updated-unit-tests-and-massive-code-improvements-1"&gt;
&lt;span id="updated-unit-tests-and-massive-code-improvements"&gt;&lt;/span&gt;&lt;h3&gt;Updated unit tests and massive code improvements&lt;/h3&gt;
&lt;p&gt;Finally, there are lots of code improvements covered with unit tests.
All to make sure that Kaylee would be solid-stable the day it reaches
the maturity version :)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Kaylee"/><category term="Python"/><category term="programming"/></entry><entry><title>Microsoft Wireless Mouse 5000: The Good, the Bad and the Ugly.</title><link href="https://zaurnasibov.com/posts/2013/05/28/ms_wireless_mouse_5000.html" rel="alternate"/><published>2013-05-28T12:00:00+03:00</published><updated>2013-05-28T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2013-05-28:/posts/2013/05/28/ms_wireless_mouse_5000.html</id><summary type="html">&lt;p class="first last"&gt;I have finally replaced my old &lt;em&gt;Defender&lt;/em&gt; mouse with a brand-new, wireless blue laser-powered &lt;em&gt;Microsoft Wireless Mouse 5000&lt;/em&gt;. Some of the reasons for picking this particular mouse are: symmetric, wireless, laser and GNU/Linux support :). A month of usage has passed and there is enough time to write a review with all tips'n'tricks which can help handling this mouse properly.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="why-ms-wireless-5000"&gt;
&lt;h2&gt;Why MS Wireless 5000?&lt;/h2&gt;
&lt;p&gt;There is an odd thing people notice, looking and my working place:
the mouse is on the left side. Usually the following question is:
&lt;em&gt;&amp;quot;Are you left-handed?&amp;quot; - &amp;quot;I'm not!&amp;quot;&lt;/em&gt;.
Long ago my father pointed out that a right-handed person can have a free
hand for other tasks (like writing with a pen) if the mouse remains in the
left hand. I am now more confident having the mouse on the left side, that
on the right. But guess what is the trick in this situation? Most modern
&lt;em&gt;ergonomical&lt;/em&gt; mice are created for right-handed persons. For example, this
nice Logitech M705:&lt;/p&gt;
&lt;img alt="logitech m705" class="align-center" src="https://zaurnasibov.com/articles/2013_05_28_ms_wireless_mouse_5000/logitech_M705.png" /&gt;
&lt;p&gt;One would find very hard times using it with the left hand.
You are probably asking &amp;quot;why not use symmetrical mouse?&amp;quot;. And that is
exactly the kind of mouse I've been using since 2005. This is my old
Defender (the blue one):&lt;/p&gt;
&lt;img alt="defender mouse" class="align-center" src="https://zaurnasibov.com/articles/2013_05_28_ms_wireless_mouse_5000/defender_orig.jpg" /&gt;
&lt;p&gt;A funny story about it: Back in 2005 I went to a store looking for a USB
mouse, as the PS/2 mouse was not working with the Linux Mandrake distro
(early 2.6 kernel) on my dorm roommate's PC.&lt;/p&gt;
&lt;p&gt;All these years the mouse was working perfectly. But then, I married and
started sharing the computer with my wife. Guess how happy she was about
the mouse on the left side :) Dragging the wired mouse here and there
created a mess with all the adjacent cables. It was clear that a time
to buy a wireless mouse had finally come.&lt;/p&gt;
&lt;p&gt;Of course, my choice would have been dramatically influenced by the old
mouse. I was looking for something:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;wireless,&lt;/li&gt;
&lt;li&gt;symmetrical,&lt;/li&gt;
&lt;li&gt;big enough to fit my palm,&lt;/li&gt;
&lt;li&gt;with side buttons&lt;/li&gt;
&lt;li&gt;and laser sensor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have considered several models, which dropped out of the list one-by-one
(for example the
&lt;a class="reference external" href="http://www.logitech.com/en-us/product/wireless-mouse-m525"&gt;Logitech M525&lt;/a&gt;
was not big enough for my palm). In the end, the only mouse that seemed to
fit all these requirements was:&lt;/p&gt;
&lt;img alt="MS Wireles 5000" class="align-center" src="https://zaurnasibov.com/articles/2013_05_28_ms_wireless_mouse_5000/mk_wm5000_large.jpg" /&gt;
&lt;/div&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h2&gt;The Good&lt;/h2&gt;
&lt;p&gt;My palm lies firmly on the mouse, the dimensions are 7x12 cm (2.8x4.6) inches.
Two AA batteries add weight which gives the overall feeling of a solid device.
The side panels are made from rubbery material. The BlueTrack laser is perfect,
it literally works on any surface (I was able to use it on my kneecap :).
Finally the wireless signal range is at least 3-4 meters (10-13 feet).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h2&gt;The Bad&lt;/h2&gt;
&lt;p&gt;I have been extensively using the side buttons on the Defender for convenient
forward and back navigation in browsers. The side buttons on Defender are
big and located directly under the thumb and the little finger.
The side buttons on MS 5000 are small and very hard to click as they are
located above of where thumb and little finger are placed:&lt;/p&gt;
&lt;img alt="ms 5000 vs. defender" class="align-center" src="https://zaurnasibov.com/articles/2013_05_28_ms_wireless_mouse_5000/defender_ms_02.jpg" /&gt;
&lt;p&gt;I'd wish that was the only problem with the buttons, but there is something
much worse: &lt;strong&gt;the middle button&lt;/strong&gt;.
The middle button has a &amp;quot;horizontal scrolling&amp;quot; feature, which can be used
by pushing the button sideways. In practice, 80% of &amp;quot;middle click&amp;quot; ends
up in horizontal scrolling, because the button is very stiff to click.
I use middle click a lot, especially when browsing (e.g. for opening the
links in background tabs). And it became a real headache to perform that
operation with this mouse. Luckily...&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h2&gt;The Ugly&lt;/h2&gt;
&lt;p&gt;Luckily, I am a Debian GNU/Linux user :) With Debian you can easily override
the keymap of any X11 device. For example, it is possible to map the
horizontal scroll buttons as a middle-click!
To do a quick temporal change to the buttons map, run &lt;tt class="docutils literal"&gt;xinput&lt;/tt&gt;. This is
the output on my computer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;zaur@z:~% xinput
⎡ Virtual core pointer                            id=2        [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer                      id=4    [slave  pointer  (2)]
⎜   ↳ HID 044e:3012                                   id=10   [slave  pointer  (2)]
⎜   ↳ PS/2 Mouse                                      id=17   [slave  pointer  (2)]
⎜   ↳ AlpsPS/2 ALPS GlidePoint                        id=18   [slave  pointer  (2)]
⎜   ↳ Microsoft Microsoft® 2.4GHz Transceiver v7.0    id=12   [slave  pointer  (2)]
⎜   ↳ Microsoft Microsoft® 2.4GHz Transceiver v7.0    id=13   [slave  pointer  (2)]
⎣ Virtual core keyboard                       id=3    [master keyboard (2)]
    ↳ Virtual core XTEST keyboard                     id=5    [slave  keyboard (3)]
    ↳ Sony Vaio Keys                                  id=6    [slave  keyboard (3)]
    ↳ Power Button                                    id=7    [slave  keyboard (3)]
    ↳ UVC Camera (05ca:183b)                          id=8    [slave  keyboard (3)]
    ↳ HID 044e:3013                                   id=9    [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard                    id=16   [slave  keyboard (3)]
    ↳ Microsoft Microsoft® 2.4GHz Transceiver v7.0    id=11   [slave  keyboard (3)]
    ↳ USB2.0 Camera                                   id=14   [slave  keyboard (3)]
    ↳ Topre Corporation Realforce 105U                id=15   [slave  keyboard (3)]
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;For some reason there are two &lt;em&gt;Microsoft Transceivers&lt;/em&gt; devices.
To find the required one, run &lt;tt class="docutils literal"&gt;xinput &lt;span class="pre"&gt;get-button-map&lt;/span&gt; device_id&lt;/tt&gt;, where
device_id is either 12 or 13, e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;zaur@z:~% xinput get-button-map 13
1 2 3 4 5 6 7 8 9 10 11 12 13
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;In order to set the desired keymap of the device, run the &lt;tt class="docutils literal"&gt;xinput&lt;/tt&gt; command
as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;xinput set-button-map 12 1 2 3 4 5 2 2 8 9 10 11 12 13
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Here, &lt;tt class="docutils literal"&gt;2&lt;/tt&gt; is the code of the middle button which overrides the codes
of &amp;quot;scroll left&amp;quot; and &amp;quot;scroll right&amp;quot; (6 and 7).&lt;/p&gt;
&lt;p&gt;To make the change permanent, create a config file (e.g. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;10-ms5000.conf&lt;/span&gt;&lt;/tt&gt;)
in &lt;tt class="docutils literal"&gt;/etc/X11/xorg.conf.d/&lt;/tt&gt; directory, with the following content:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Section &amp;quot;InputClass&amp;quot;
        Identifier      &amp;quot;MS 5000&amp;quot;
        MatchProduct    &amp;quot;Microsoft Microsoft® 2.4GHz Transceiver v7.0&amp;quot;
        Option          &amp;quot;ButtonMapping&amp;quot; &amp;quot;1 2 3 4 5 2 2 8 9 10 11 12 13&amp;quot;
EndSection
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="the-conclusion"&gt;
&lt;h2&gt;The conclusion&lt;/h2&gt;
&lt;p&gt;Microsoft Wireless Mouse 5000 is 75% worth its money (35EUR),
especially for users who are looking for a big and symmetric mouse.&lt;/p&gt;
&lt;p&gt;It has a minor (small side buttons) and a major (stiff middle click) glitches,
which are not that bad to ignore this mouse.&lt;/p&gt;
&lt;p&gt;I hope you enjoyed the review. Feel free to comment and share you mouse
experience!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Microsoft"/><category term="mouse"/><category term="Linux"/><category term="life"/></entry><entry><title>PyRegs: The Python Regex Debugger</title><link href="https://zaurnasibov.com/posts/2013/05/22/pyregs.html" rel="alternate"/><published>2013-05-22T12:00:00+03:00</published><updated>2013-05-22T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2013-05-22:/posts/2013/05/22/pyregs.html</id><summary type="html">&lt;p class="first last"&gt;Long ago, I learned the regular expressions in order to write a simple syntax highlighting engine. Regular expressions are not hard to master, but take time to practice. &lt;a class="reference external" href="http://kodos.sourceforge.net/"&gt;Kodos&lt;/a&gt; was the regex debugger of my choice, as it was written in Python. All these years Kodos was a &amp;quot;must have&amp;quot; tool on my development machines. Suddenly with the new version of Debian operating system, Kodos was not in the repositories anymore! Why? Kodos is based on QT3 widgets toolkit, which is a bit outdated nowadays (QT5 has been released recently) and was removed from Debian 7.0 (&amp;quot;Wheezy&amp;quot;). That is how I decided to write a small Python regex debugger in Python 3 and its de-facto standard &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Tkinter"&gt;Tkinter&lt;/a&gt; bindings to the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Tk_(framework)"&gt;Tk&lt;/a&gt; GUI toolkit.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="pyregs-v0-1"&gt;
&lt;h2&gt;PyRegs v0.1&lt;/h2&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Written in Python 3&lt;/li&gt;
&lt;li&gt;Tkinter widgets, which are available on most of the Python-supported
platforms.&lt;/li&gt;
&lt;li&gt;Python 3 regular expressions with Unicode support.&lt;/li&gt;
&lt;li&gt;Easy matches and grouped values navigation.&lt;/li&gt;
&lt;li&gt;Regex analysis in separate thread.&lt;/li&gt;
&lt;li&gt;Quick regex reference.&lt;/li&gt;
&lt;li&gt;Licensed under GPLv3.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pyregs v0.1 is ready, you are encouraged to give it a try!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installation"&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pip install pyregs
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Or clone the repository from &lt;a class="reference external" href="https://github.com/BasicWolf/pyregs"&gt;https://github.com/BasicWolf/pyregs&lt;/a&gt;&lt;/p&gt;
&lt;div class="section" id="screenshots"&gt;
&lt;h3&gt;Screenshots&lt;/h3&gt;
&lt;p&gt;Match tab:&lt;/p&gt;
&lt;img alt="pyregs v0.1" class="align-center" src="https://zaurnasibov.com/articles/2013_05_22_pyregs/pyregs_v0.1_0.png" /&gt;
&lt;p&gt;Grouping by name:&lt;/p&gt;
&lt;img alt="pyregs grouping" class="align-center" src="https://zaurnasibov.com/articles/2013_05_22_pyregs/pyregs_v0.1_1.png" /&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="Python"/></entry><entry><title>Thoughts about XML structure: elements vs. attributes</title><link href="https://zaurnasibov.com/posts/2013/05/18/thoughts_on_xml_structure.html" rel="alternate"/><published>2013-05-18T12:00:00+03:00</published><updated>2013-05-18T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2013-05-18:/posts/2013/05/18/thoughts_on_xml_structure.html</id><summary type="html">&lt;p class="first last"&gt;Exploring XML elements versus attributes.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;XML defines no rules about using elements or attributes in paricular case. For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;firstname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Alex&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;lastname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Black&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;is as valid as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;firstname&amp;gt;&lt;/span&gt;Alex&lt;span class="nt"&gt;&amp;lt;/firstname&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;lastname&amp;gt;&lt;/span&gt;Black&lt;span class="nt"&gt;&amp;lt;/lastname&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Are there any general guidelines on when attributes or elements should be used?
Let's explore various cases to find out the best solution of the problem.&lt;/p&gt;
&lt;p&gt;Consider the example above. Should one use the attributes or elements
in this case? Unless you care about the size of the data, it doesn't matter
at all!
And that is true for this particular case without a context.
We have no knowledge about how the &lt;tt class="docutils literal"&gt;&amp;lt;user&amp;gt;&lt;/tt&gt; data is &lt;strong&gt;processed&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="processing-matters"&gt;
&lt;h2&gt;Processing matters&lt;/h2&gt;
&lt;p&gt;XML is meant to be both human and machine readable. Would you agree that
&amp;quot;machine readable&amp;quot; matters more, because every day machines automatically
process tons of XML data?&lt;/p&gt;
&lt;p&gt;For example, the first steps of processing XHTML &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt; may look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;|----------|   |------------|   |-----------------|
| XML data |--&amp;gt;| XML parser |--&amp;gt;| XHTML processor |--&amp;gt; ...
|----------|   |------------|   |-----------------|
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Note, that the &lt;em&gt;XML parser&lt;/em&gt; knows nothing about the data except that
it is XML. It doesn't care whether the data is described via the
elements or attributes. In fact, the XML parser is able to parse any
data, whether it is an XHTML document, RSS channell, OpenDocument container
and so on.
The XML parser transforms the input data into objects in memory which are
passed to the &lt;em&gt;XHTML processor&lt;/em&gt; which contains the logic of dealing
with these objects.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="xml-data"&gt;
&lt;h2&gt;XML data&lt;/h2&gt;
&lt;p&gt;Consider an ordered list which starts with a &amp;quot;100&amp;quot; bullet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ol&lt;/span&gt; &lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;100&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Coffee&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Milk&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ol&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The XHTML processor, knows that the &lt;tt class="docutils literal"&gt;&amp;lt;ol&amp;gt;&lt;/tt&gt; tag represents an ordered
list, and the nested &lt;tt class="docutils literal"&gt;&amp;lt;li&amp;gt;&lt;/tt&gt; tags are the list elements with the data.
The processor also expects that the &lt;tt class="docutils literal"&gt;&amp;lt;ol&amp;gt;&lt;/tt&gt; tag data may contain specific
attribute which describe the list, e.g. &lt;tt class="docutils literal"&gt;&amp;quot;start&amp;quot;&lt;/tt&gt;
Note, that changing the value of the &lt;tt class="docutils literal"&gt;start&lt;/tt&gt; attribute does not interfere
with the data (the list items).&lt;/p&gt;
&lt;p&gt;Now, let's create an unordered list:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Tee&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Soda&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The XHTML processor will also parse this data as a list, because it is
&lt;em&gt;aware&lt;/em&gt; of the &lt;tt class="docutils literal"&gt;&amp;lt;ul&amp;gt;&lt;/tt&gt; tag and its contents.
The HTML standard has the third &lt;tt class="docutils literal"&gt;&amp;lt;dt&amp;gt;&lt;/tt&gt; &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; tag which describes a definision
list.&lt;/p&gt;
&lt;p&gt;Let's think of an interesting design task: how would you design an XML
format which stores any kind of lists unknown to the processor module?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;|----------|   |------------|   |----------------|
| XML data |--&amp;gt;| XML parser |--&amp;gt;| Our  processor |--&amp;gt; ...
|----------|   |------------|   |----------------|
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And that is where attributes can be very useful:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;list&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;item=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Alex&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;lastname&amp;gt;&lt;/span&gt;Black&lt;span class="nt"&gt;&amp;lt;/lastname&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;John&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Brown&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/users&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The processor is not aware of the &lt;tt class="docutils literal"&gt;&amp;lt;users&amp;gt;&lt;/tt&gt; tag. But it knows that if
an element contains the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type=&amp;quot;list&amp;quot;&lt;/span&gt;&lt;/tt&gt; attribute (and value), then the
&lt;tt class="docutils literal"&gt;item&lt;/tt&gt; attribute would describe the list items to look for. What if
we wanted to make a list with multiple selected items? The attributes can
handle this situation as well:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;list&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;item=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;selected=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Alex&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;lastname&amp;gt;&lt;/span&gt;Black&lt;span class="nt"&gt;&amp;lt;/lastname&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;selected=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;user&amp;gt;&lt;/span&gt;...&lt;span class="nt"&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/users&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="attributes-as-metadata"&gt;
&lt;h2&gt;Attributes as metadata&lt;/h2&gt;
&lt;p&gt;Metadata is a data which describes some other data. In all the examples
above, the attributes contained the metadata information. Removing the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;type=&amp;quot;list&amp;quot;&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;item=&amp;quot;user&amp;quot;&lt;/span&gt;&lt;/tt&gt; attributes from the &lt;tt class="docutils literal"&gt;&amp;lt;users&amp;gt;&lt;/tt&gt; tag
will affect the way how the data is processed, but the original data
is intact.&lt;/p&gt;
&lt;p&gt;In my opinion the attributes are perfect for metadata, and a person
designing an XML document format should simply take the discussion of
&amp;quot;Attributes vs. elements&amp;quot; to the &amp;quot;Data and metadata&amp;quot; level.&lt;/p&gt;
&lt;p&gt;Eager to hear your comments!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="footnotes"&gt;
&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;HTML is not a subset of XML, while XHTML is.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.w3schools.com/html/html_lists.asp"&gt;http://www.w3schools.com/html/html_lists.asp&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="XML"/></entry><entry><title>Kaylee</title><link href="https://zaurnasibov.com/posts/2012/08/28/kaylee.html" rel="alternate"/><published>2012-08-28T12:00:00+03:00</published><updated>2012-08-28T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2012-08-28:/posts/2012/08/28/kaylee.html</id><summary type="html">&lt;p class="first last"&gt;I just returned from my summer vacation and can finally state: another summer is over. But wonderful summer it was! I finally graduated and got a Master's degree in computer science. I cycled a lot and upgraded my MTB skills. I read lot of fiction. And somewhere between work, sports reading and sleeping was &lt;strong&gt;Kaylee&lt;/strong&gt;, a distributed and volunteer in-browser computing framework.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="kaylee-is"&gt;
&lt;h2&gt;Kaylee is&lt;/h2&gt;
&lt;p&gt;Kaylee is a Python and JavaScript framework for developing in-browser
distributed and volunteer computing applications that allows programmers
to concentrate on business logic by leaving all the computational nodes
handling to Kaylee.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="why"&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;Do you have a wast amount of data to be analyzed? Are you deciphering
a life-and-death matter e-mail? Do you have a smart algorithm to find
the question with the known &amp;quot;42&amp;quot; answer? Do you have computing resources
to do any of it? If the answer to the last question is &amp;quot;No! :(&amp;quot; then Kaylee
is the right solution.&lt;/p&gt;
&lt;p&gt;With Kaylee you are able to distribute the computation between millions
of Internet users and they even don't have to know that! This is how it
works:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;A user opens a link / enters a web site via a modern browser.&lt;/li&gt;
&lt;li&gt;Kaylee is started in background.&lt;/li&gt;
&lt;li&gt;The application and the data are downloaded from the server.&lt;/li&gt;
&lt;li&gt;The application solves the given tasks.&lt;/li&gt;
&lt;li&gt;The results are sent back to the server.&lt;/li&gt;
&lt;li&gt;Getting and solving the tasks continues as long as the user stays on
the page or there are no more tasks left.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All this happens via JavaScript code executed in a separate so-called
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Web_worker"&gt;Web Worker&lt;/a&gt; thread. That's
how Kaylee does not interfere with the browser's main JavaScript loop
and the user interface is intact.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="get-it"&gt;
&lt;h2&gt;Get it!&lt;/h2&gt;
&lt;p&gt;The repository is located at &lt;a class="reference external" href="http://github.com/basicwolf/kaylee"&gt;http://github.com/basicwolf/kaylee&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="release-history"&gt;
&lt;h2&gt;Release history&lt;/h2&gt;
&lt;p&gt;TODO: Kaylee v0.3 &amp;lt;kaylee_0_3&amp;gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="projects"/><category term="Python"/><category term="CoffeeScript"/><category term="Kaylee"/></entry><entry><title>I have graduated</title><link href="https://zaurnasibov.com/posts/2012/07/08/i_have_graduated.html" rel="alternate"/><published>2012-07-08T12:00:00+03:00</published><updated>2012-07-08T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2012-07-08:/posts/2012/07/08/i_have_graduated.html</id><summary type="html">&lt;p class="first last"&gt;I have graduated!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Ladies and Gentlemen!&lt;/p&gt;
&lt;p&gt;I have graduated! Four years of master studies at the University of Eastern
Finland and finally, it is done. I'd like to thank everyone who helped and
supported me these years, my family, my friends, my colleagues at Blancco
and first of all my supervisor Dr. Tomi Kinnunen.&lt;/p&gt;
&lt;p&gt;The thesis is about Voice activity detection (VAD). You may be surprised
to hear that you use it every day when speaking by mobile phone or Skype.
It is a small module that detects whether the input signal from a microphone
contains speech or not. Consider a typical phone conversation: you are
speaking for half of the time and listen for another half. That's when
a VAD decides that there is no need to transfer any data from your microphone
to another end of the conversation. It saves your battery and network
bandwidth a lot.&lt;/p&gt;
&lt;p&gt;So, without any further hesitation, here is the
&lt;a class="reference external" href="https://zaurnasibov.com/articles/2012_07_08_i_have_graduated/attachments/2012_MSc_Nasibov_Zaur.pdf"&gt;Download&lt;/a&gt; link.
I hope you will my thesis interesting and will enjoy reading it.&lt;/p&gt;
&lt;p&gt;-- Zaur.&lt;/p&gt;
</content><category term="Articles"/><category term="projects"/><category term="life"/><category term="science"/></entry><entry><title>C's heritage: bitwise and equality operators</title><link href="https://zaurnasibov.com/posts/2011/12/29/cs_heritage_bitwise_and_equality_operators.html" rel="alternate"/><published>2011-12-29T12:00:00+02:00</published><updated>2011-12-29T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2011-12-29:/posts/2011/12/29/cs_heritage_bitwise_and_equality_operators.html</id><summary type="html">&lt;p class="first last"&gt;The design of C made by Brian Kernighan and Dennis Ritchie has influenced the whole software and hardware industry. Sometimes you can feel the heritage of C even in modern high-level dynamic languages like Javascript.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I've stumbled in a Javascript situation where bitwise operators were used.
Logically, a bitwise operator should have a higher precedence than an
equality operator, e.g:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;We&amp;#39;ve got it!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But it looks like that this code would work the other way, as in JavaScript
bitwise operators have lower precedence than equality operators do (see
Mozilla's JS reference). The code above would always return 0 for any valid
numerical val, because the result of val &amp;amp; true is 0. So, the proper way
would be to put parenthesis around bitwise expression:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;We&amp;#39;ve got it!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;I dug up the history of the question and it seems like this behaviour
comes from the age of K&amp;amp;R's C:&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;Early C had no separate operators for &amp;amp; and &amp;amp;&amp;amp; or | and ||. (Got that?)
Instead it used the notion (inherited from B and BCPL) of &amp;quot;truth-value
context&amp;quot;: where a Boolean value was expected, after &amp;quot;if&amp;quot; and &amp;quot;while&amp;quot;
and so forth, the &amp;amp; and | operators were interpreted as &amp;amp;&amp;amp; and || are
now; in ordinary expressions, the bitwise interpretations were used.
It worked out pretty well, but was hard to explain. (There was the notion
of &amp;quot;top-level operators&amp;quot; in a truth-value context.)&lt;/p&gt;
&lt;p&gt;The precedence of &amp;amp; and | were as they are now.
...&lt;/p&gt;
&lt;p&gt;In retrospect it would have been better to go ahead and change the
precedence of &amp;amp; to higher than ==, but it seemed safer just to split
&amp;amp; and &amp;amp;&amp;amp; without moving &amp;amp; past an existing operator. (After all, we
had several hundred kilobytes of source code, and maybe 3
installations....)&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Dennis Ritchie &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In terms of logical statement in C:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Makes perfect sense. But it doesn't make any in terms of bitwise logic.&lt;/p&gt;
&lt;p&gt;C++, Java, Objective-C, PHP, C# and finally Javascript have it the same
way. Python, Ruby, Go have it the other way around.&lt;/p&gt;
&lt;p&gt;Do you know any reasons (apart from the one that comes from C's heritage)
which made programming languages' designers to follow C's precedence rules?&lt;/p&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.lysator.liu.se/c/dmr-on-or.html"&gt;http://www.lysator.liu.se/c/dmr-on-or.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="C"/><category term="JavaScript"/></entry><entry><title>Python: comparing to None</title><link href="https://zaurnasibov.com/posts/2011/08/01/python_comparing_to_none.html" rel="alternate"/><published>2011-08-01T12:00:00+03:00</published><updated>2011-08-01T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2011-08-01:/posts/2011/08/01/python_comparing_to_none.html</id><summary type="html">&lt;p class="first last"&gt;Python's documentation states that one has to use the &lt;tt class="docutils literal"&gt;is&lt;/tt&gt; operator to compare a variable to &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;. What happens when you avoid that advice?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Consider a class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__len__&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="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_len&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Next, the usage of the class is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Queue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# at this point, you want to check if q is None&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
   &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The confusing thing is that &lt;tt class="docutils literal"&gt;doSomething()&lt;/tt&gt; is actually called! And
that is because &lt;tt class="docutils literal"&gt;len(q) == 0&lt;/tt&gt;!&lt;/p&gt;
&lt;p&gt;Instead, use the &lt;tt class="docutils literal"&gt;is None&lt;/tt&gt; comparison:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="Python"/></entry><entry><title>Inside Python: understanding os.listdir()</title><link href="https://zaurnasibov.com/posts/2011/05/08/inside_python_understanding_os_listdir.html" rel="alternate"/><published>2011-05-08T12:00:00+03:00</published><updated>2011-05-08T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2011-05-08:/posts/2011/05/08/inside_python_understanding_os_listdir.html</id><summary type="html">&lt;p class="first last"&gt;If you've been using python for a long time, then you surely know that &lt;tt class="docutils literal"&gt;os.listdir()&lt;/tt&gt; function returns an unsorted list of file names. I didn't care much until facing a situation, in which the sorted-sequential processing of files was crucial, and I could not remember whether the previous file processing were done in sorted order. Well, luckily they were. But hey, this is a little bit annoying, isn't it? Why &lt;tt class="docutils literal"&gt;os.listdir()&lt;/tt&gt; returns an unsorted list of files? Would you like to find out?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;To answer this question, one has to get inside Python's source.
The stable Python 3.2 could be found
&lt;a class="reference external" href="http://www.python.org/download/releases/3.2"&gt;here&lt;/a&gt;.
The &lt;tt class="docutils literal"&gt;os.py&lt;/tt&gt; module in source archive's Lib directory doesn't contain the
&lt;tt class="docutils literal"&gt;listdir()&lt;/tt&gt; function. Yet, the very place to look comes from:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;posix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Let's take a look on &lt;tt class="docutils literal"&gt;Modules/posixmodule.c&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Pay attention to the comments!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;posix_listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyObject&lt;/span&gt;&lt;span class="w"&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="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* line 2323 */&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* POSIX-related code, supposed to start from line 2574 */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;dirp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;opendir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* Opening directory for which os.listdir() was called */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;opendir()&lt;/tt&gt; function opens a directory stream corresponding to the
directory name, and returns a pointer to the directory stream. The stream
is positioned at the first entry in the directory.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Linux &lt;tt class="docutils literal"&gt;opendir()&lt;/tt&gt; man page&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="cm"&gt;/* continuing posix_listdir() */&lt;/span&gt;
&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* A crucial readdir() call */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;d_name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* skipping &amp;#39;.&amp;#39; and &amp;#39;..&amp;#39; */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NAMLEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;d_name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAMLEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg_is_unicode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyUnicode_DecodeFSDefaultAndSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;d_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAMLEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PyBytes_FromStringAndSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;d_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NAMLEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Py_CLEAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PyList_Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* appending found path to the return list */&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Py_DECREF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Py_CLEAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;readdir()&lt;/tt&gt; function returns a pointer to a dirent structure
representing the next directory entry in the directory stream pointed
to by dirp. It returns NULL on reaching the end of the directory stream
or if an error occurred.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Linux &lt;tt class="docutils literal"&gt;readdir()&lt;/tt&gt; man page&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Linux, the dirent structure is defined as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;dirent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;ino_t&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;d_ino&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="cm"&gt;/* inode number */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;off_t&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;d_off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="cm"&gt;/* offset to the next dirent */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d_reclen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="cm"&gt;/* length of this record */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;d_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="cm"&gt;/* type of file; */&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="n"&gt;d_name&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/* filename */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;As you can see, &lt;tt class="docutils literal"&gt;readdir()&lt;/tt&gt; loops through a list of dirent structures,
and there is no quarantie that the structures will be somehow sorted.&lt;/p&gt;
&lt;p&gt;So, how one can act when a sorted &lt;tt class="docutils literal"&gt;os.listdir()&lt;/tt&gt; behaviour is required?
Pretty simple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;lst&lt;/span&gt; &lt;span class="o"&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;# sorted files only&lt;/span&gt;
&lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&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;f&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="c1"&gt;# sorted dirs only&lt;/span&gt;
&lt;span class="n"&gt;dirs&lt;/span&gt; &lt;span class="o"&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;d&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&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;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Another Python mystery revealed!&lt;/p&gt;
</content><category term="Articles"/><category term="programming"/><category term="Linux"/><category term="Python"/><category term="C"/></entry><entry><title>Opera extensions: YouTube suite</title><link href="https://zaurnasibov.com/posts/2010/12/31/opera_extensions_youtube_suite.html" rel="alternate"/><published>2010-12-31T12:00:00+02:00</published><updated>2010-12-31T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-12-31:/posts/2010/12/31/opera_extensions_youtube_suite.html</id><summary type="html">&lt;p class="first last"&gt;Ah, Opera! My favourite browser has been recently update to version 11. There are lots of new beautiful features, like Presto 2.7 engine, improved HTML5 support, tab stacking, mouse gestures visualisation, smart address field, Extensions and much more. Opera 11 has been officially out for just two weeks, and there are already 300 &lt;a class="reference external" href="http://www.opera.com/addons/extensions"&gt;Extensions&lt;/a&gt; (also known as &amp;quot;Add-ons&amp;quot; in Firefox and (surprise!) &amp;quot;Extensions&amp;quot; in Chrome) available!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;So, the number of extensions is growing rapidly. But how can one benefit
from an extension? Well, if you are a user-js geek, first, think of Opera
extensions as of always up-to-date 3d party user-js scripts. The provided
browser communication API for managing windows, tabs, toolbars, icons etc.
makes a complete picture. Yet, a user-js is just a script that can be initially
triggered at various page loading stages. Every extension, for starters,
has it's own process constantly running in background... But why discuss
technical issues? I'm sure a geek can find a way to &lt;a class="reference external" href="http://net.tutsplus.com/tutorials/how-to-create-an-opera-extension-from-scratch"&gt;create an extension
in 30 minutes&lt;/a&gt;.
(Hopefully all geeks have followed that link :)&lt;/p&gt;
&lt;p&gt;I believe, there is no need to explain, what YouTube is. The widely-used
video hosting service already got it's fair share of Opera extensions.
Would you like to find out what features these wonderful extensions are
capable of?&lt;/p&gt;
&lt;div class="section" id="downloading-videos"&gt;
&lt;h2&gt;Downloading videos&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Easy Youtube Downloader for Opera&lt;/strong&gt; &lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/easy-youtube-video-downloader-for-opera"&gt;[⇩]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The extension provides an easy and convenient way to download YouTube
videos in all available formats, including mp3 (through the
&lt;a class="reference external" href="http://videodroid.org"&gt;videodroid.org&lt;/a&gt; service).&lt;/p&gt;
&lt;img alt="Opera Video Downloader" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/easy_youtube_video_downloader.png" /&gt;
&lt;p&gt;The extension creates a &lt;strong&gt;Download As&lt;/strong&gt;: drop-down list with one or more
direct links to video files. If you're not familiar with &amp;quot;p&amp;quot; notation,
&amp;quot;p&amp;quot; stands for horizontal scan lines of display resolution (also known
as number of vertical resolution pixels) &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;. The very basic idea here
is: the bigger - the better.&lt;/p&gt;
&lt;p&gt;In case you don't know what should be chosen from 360p options &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;,
a simple answer would be: &amp;quot;360p FLV has better resolution&amp;quot;. Consequently,
the file size will differ a bit too. For example, the Opera Unite intro
video's size is 4.4 MB (MP4) versus 5.2 MB (FLV).&lt;/p&gt;
&lt;p&gt;Bored of watching low-res movies? Hit highest available &lt;strong&gt;HD&lt;/strong&gt; option
(720p or 1080p) and download the clip in High Definition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Easy Youtube Downloader&lt;/strong&gt; is not the one of it's kind, yet is the best
available. Even with minor advantages (an icon on download button and
&amp;quot;MP3&amp;quot; download option) it beats the &lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/fastesttube-youtube-video-downloader"&gt;Fastest Youtube Video Downloader&lt;/a&gt;
and &lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/youtube-downloader-2"&gt;Youtube Downloader 2&lt;/a&gt;
extensions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="watching-videos"&gt;
&lt;h2&gt;Watching videos&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Focus on Videos&lt;/strong&gt;
&lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/focus-on-videos"&gt;[⇩]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Focus on Videos is a nice extension that deems everything but the video
you're watching. As a video starts playing, the extension turns this&lt;/p&gt;
&lt;img alt="Focus On Video" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/focus_on_video_1.png" /&gt;
&lt;p&gt;Into this:&lt;/p&gt;
&lt;img alt="Focus On Video" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/focus_on_video_2.png" /&gt;
&lt;p&gt;You can also toggle that by clicking a control button with a green lamp
icon on it, or hitting Escape button (yeah, the one that's in the right
top corner of the keyboard :).&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;This focus effect is especially perfect if browser is running in Full
screen mode.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;YouTube AdsFree&lt;/strong&gt;
&lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/youtube-adsfree"&gt;[⇩]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An extension that makes user's dream come true. As a user, I'm very
embarrassed with these kind of ads:&lt;/p&gt;
&lt;img alt="Adware" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/ad.png" /&gt;
&lt;p&gt;Fortunately, YouTube AdsFree extension solves the problem once and for all.
Eventually Google will have to invent another way of showing YouTube ads to
Opera users.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;You have to re-open the page with a video to make extension work.
(In this case, &lt;tt class="docutils literal"&gt;Ctrl+W&lt;/tt&gt;; &lt;tt class="docutils literal"&gt;Ctrl+Z&lt;/tt&gt; will save you a couple of mouse
clicks!)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;LoopTube&lt;/strong&gt;
&lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/looptube"&gt;[⇩]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A minor, yet often required feature that a standard player lacks: video
playback loop. LoopTube is a small extension that makes our live easier
by providing that feature. You can manage it's behaviour via additional
control button:&lt;/p&gt;
&lt;img alt="Loop Tube" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/loop_tube.png" /&gt;
&lt;p&gt;&lt;strong&gt;Youtube Autoplay Killer&lt;/strong&gt;
&lt;a class="reference external" href="https://addons.opera.com/addons/extensions/details/youtube-autoplay-killer"&gt;[⇩]&lt;/a&gt;
Another heavily demanded feature. Not only the extension disables auto-play,
it also holds the download process (very useful, e.g. if you just want to
read the comments, yet very annoying, if you have a slow connection and want
to cache the video before watching it).&lt;/p&gt;
&lt;p&gt;A small drawback: the extension doesn't work with HTML5 videos (which are
discussed below), but that's version 1.0 we're talking about!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="searching-for-videos"&gt;
&lt;h2&gt;Searching for videos&lt;/h2&gt;
&lt;p&gt;YouTube WebM Enablr
&lt;a class="reference external" href="http://addons.opera.com/addons/extensions/details/youtube-webm-enablr"&gt;[⇩]&lt;/a&gt;
Do you know that the &lt;tt class="docutils literal"&gt;&amp;lt;video&amp;gt;&lt;/tt&gt; tag was proposed by Opera back in 2007?
That was almost 4 years ago! Nowadays we're slowly moving from Adobe
Flash-embedded videos to HTML5 video system.&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
WebM is a multimedia container format designed to provide a royalty-free,
high-quality open video compression format for use with HTML5 video &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;.&lt;/blockquote&gt;
&lt;p&gt;In my opinion, the key words here are: &lt;strong&gt;royalty-free&lt;/strong&gt;, &lt;strong&gt;high-quality&lt;/strong&gt;,
&lt;strong&gt;open&lt;/strong&gt;. There were loud debates (I wonder if they are finished) about the
format &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-5"&gt;[5]&lt;/a&gt;. Still, what concerns Opera users is that WebM is fully supported
by Opera, and if you have a trouble running Adobe Flash plug-in, then
&lt;em&gt;WebM Enablr&lt;/em&gt; is just what the doctor ordered.&lt;/p&gt;
&lt;p&gt;The steps are simple:
1. Install the extension.
2. Search for videos.
3. Watch video without Flash plugin involved.&lt;/p&gt;
&lt;img alt="Html5 Video extension" class="align-center" src="https://zaurnasibov.com/articles/2010_12_31_opera_extensions_youtube_suite/html5_video.png" /&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;WebM videos only! There are plenty of YouTube clips that haven't been
encoded in WebM yet. And don't rely on playlist-based search results.
Those still might require Adobe Flash plugin.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="so-many-of-them"&gt;
&lt;h2&gt;So many of them...&lt;/h2&gt;
&lt;p&gt;Of course, this is not the complete list of YouTube-specific extensions.
Hopefully this small suite will suit your basic needs. Don't hesitate
a moment to &lt;a class="reference external" href="https://addons.opera.com/en/search/?query=youtube&amp;amp;order=new&amp;amp;language=any&amp;amp;no_promo_box=1"&gt;try them all&lt;/a&gt;
!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Wikipedia: 720p&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Wikipedia: Flash Video&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Wikipedia: MPEG-4&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Wikipedia: WebM&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Wikipedia: Default HTML5 video format debate&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles none"/><category term="Opera"/></entry><entry><title>Assembler for beginners</title><link href="https://zaurnasibov.com/posts/2010/08/08/assembler_for_beginners.html" rel="alternate"/><published>2010-08-08T12:00:00+03:00</published><updated>2010-08-08T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-08-08:/posts/2010/08/08/assembler_for_beginners.html</id><summary type="html">&lt;p class="first last"&gt;About introductory book to programming using assembly language.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;As a part of my work in &lt;a class="reference external" href="http://www.blancco.com"&gt;Blancco&lt;/a&gt;, I encounter a very low-level code.
By low-level I mean Assembler (AT&amp;amp;T syntax) for x86 processors family.
A bit shame for computer scientist: I have NO experience in assembly.
Thus, I spent a lot of time looking for good tutorials.
Sounds interesting?&lt;/p&gt;
&lt;p&gt;Let me introduce you to Programming from the Ground Up Book by Jonathan
Bartlett. What is so special about it?&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
This is an introductory book to programming and computer science using
assembly language. It assumes the reader has never programmed before,
and introduces the concepts of variables, functions, and flow control.&lt;/blockquote&gt;
&lt;p&gt;I've spent less than half an hour of reading it and already know much much
more about processor's registers, interrupts, assembly language basics.
The code examples are clear and explained very well. The language of the
book is easy to understand and very interesting to read.
I'd like to thank the author for this achievement. Great work!&lt;/p&gt;
</content><category term="Articles"/><category term="programming"/><category term="Assembler"/></entry><entry><title>Linux, it's time to wake up!</title><link href="https://zaurnasibov.com/posts/2010/05/22/linux_time_to_wake_up.html" rel="alternate"/><published>2010-05-22T12:00:00+03:00</published><updated>2010-05-22T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-05-22:/posts/2010/05/22/linux_time_to_wake_up.html</id><summary type="html">&lt;p class="first last"&gt;Back in my &amp;quot;Windows&amp;quot; times, I was a fan of Foobar2000 music player. One of my favourite plug-ins was &amp;quot;Alarm&amp;quot;, which could turn user's computer on during &amp;quot;suspend&amp;quot; state. So, I could switch my laptop to &amp;quot;sleep&amp;quot; mode, and be awaken in the morning by music from Foobar's playlist :) Is it possible to reproduce a similar trick in Linux? It depends on your hardware. Let's give it a try!&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="what-is-rtc-and-acpi"&gt;
&lt;h2&gt;What is RTC and ACPI?&lt;/h2&gt;
&lt;p&gt;A Real Time Clock (RTC) alarm is a feature that can be used to allow a
computer to 'wake up' after shut down to execute tasks every day or on a
certain day. It can sometimes be found in the 'Power Management' section
of a motherboard's BIOS setup &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In computing, the Advanced Configuration and Power Interface (ACPI)
specification provides an open standard for unified operating system-centric
device configuration and power management. ACPI, first released in December
1996, defines platform-independent interfaces for hardware discovery,
configuration, power management and monitoring &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ACPI allows control of power management from within the operating system.
The previous industry standard for power management, Advanced Power Management
(APM), is controlled at the BIOS level. APM is activated when the system
becomes idle: the longer the system idles, the less power it consumes (e.g.
screen saver vs. sleep vs. suspend). In APM, the operating system has no
knowledge of when the system will change power states &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;ACPI can typically be configured from within the operating system. This is
unlike APM where configuration often involves rebooting and entering the
BIOS configuration screens to set parameters.&lt;/p&gt;
&lt;p&gt;The ACPI specification defines seven states (so-called global states) for
an ACPI-compliant computer-system &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt;. Some of them are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;G0 (S0)&lt;/strong&gt; Working.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G1&lt;/strong&gt; Sleeping (subdivides into the four states S1 through S4).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G1/S3&lt;/strong&gt; Commonly referred to as Standby, Sleep, or Suspend to RAM.
RAM remains powered&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G1/S4&lt;/strong&gt; Hibernation or Suspend to Disk. All content of main memory
is saved to non-volatile memory such as a hard drive, and is powered down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;G2 (S5)&lt;/strong&gt; Soft Off. G2, S5, and Soft Off are synonyms. G2 is almost the
same as G3 Mechanical Off, but some components remain powered so the
computer can &amp;quot;wake&amp;quot; from input from the keyboard, clock, modem, LAN, or
USB device.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If implemented, the Real Time Clock alarm must generate a hardware wake
event when in the sleeping state. The RTC can be programmed to generate
an alarm. An enabled RTC alarm can be used to generate a wake event when
the system is in a sleeping state.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="setting-up-the-wakeup-alarm"&gt;
&lt;h2&gt;Setting up the wakeup alarm&lt;/h2&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Open a terminal and switch to root su root.&lt;/li&gt;
&lt;li&gt;Check if rtc is available (kernel 2.6.22 and higher):
&lt;tt class="docutils literal"&gt;ls /sys/class/rtc/rtc0/&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Look for the wakealarm file.&lt;/li&gt;
&lt;li&gt;Initialize the alarm via &lt;tt class="docutils literal"&gt;echo 0 &amp;gt; /sys/class/rtc/rtc0/wakealarm&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Check if it has been initialzed: &lt;tt class="docutils literal"&gt;cat /proc/driver/rtc&lt;/tt&gt;. At this
point, the output should be similar to:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;rtc_time&lt;span class="w"&gt;      &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;09&lt;/span&gt;:30:05
rtc_date&lt;span class="w"&gt;      &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2010&lt;/span&gt;-05-22
alrm_time&lt;span class="w"&gt;     &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;09&lt;/span&gt;:34:43
alrm_date&lt;span class="w"&gt;     &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;****-**-22
alarm_IRQ&lt;span class="w"&gt;     &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;no
alrm_pending&lt;span class="w"&gt;  &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;no
24hr&lt;span class="w"&gt;          &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;yes
periodic_IRQ&lt;span class="w"&gt;  &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;no
update_IRQ&lt;span class="w"&gt;    &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;no
HPET_emulated&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;yes
DST_enable&lt;span class="w"&gt;    &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;no
periodic_freq&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;
batt_status&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;okay
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The rtc alarm is now ready to be set up. Wakealarm accepts the number of
seconds since Jan 1, 1970 (this is known as &amp;quot;unix time&amp;quot;, &amp;quot;POSIX time&amp;quot; or
&amp;quot;epoch time&amp;quot;).&lt;/p&gt;
&lt;p&gt;You must make sure that your BIOS clock is set to UTC time - not localtime
- otherwise it will wakeup at the wrong time. However, it is still possible
if the BIOS clock is set to localtime (likely if you also run windows); see
the section below for how to set the alarm correctly when the BIOS clock is
in localtime. If you want to change the wakealarm time, you will need to
write the new wakealarm time to the BIOS.&lt;/p&gt;
&lt;ol class="arabic simple" start="6"&gt;
&lt;li&gt;A simple way to set the alarm to current time + 1 minute is:
&lt;tt class="docutils literal"&gt;echo &amp;quot;+60&amp;quot; &amp;gt; /sys/class/rtc/rtc0/wakealarm&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;Check if the alarm has been set up:
&lt;tt class="docutils literal"&gt;cat /proc/driver/rtc&lt;/tt&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;...
alarm_IRQ&lt;span class="w"&gt;      &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;yes
...
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;ol class="arabic simple" start="8"&gt;
&lt;li&gt;Now, suspend or shut down your computer. And wait until it wakes up in
less than a minute :)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can find more information about the topic at
&lt;a class="reference external" href="http://www.mythtv.org/wiki/ACPI_Wakeup"&gt;MythTV.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Be careful with the experiments!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Real-time_clock_alarm"&gt;Wikipedia.org: Real-time alarm&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface"&gt;Wikipedia.org: ACPI&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Advanced_Configuration_and_Power_Interface#Power_States"&gt;Wikipedia.org: ACPI power states&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.tldp.org/HOWTO/ACPI-HOWTO/aboutacpi.html"&gt;About ACPI by Emma Jane Hogbin&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Linux"/><category term="ACPI"/></entry><entry><title>Why Opera?</title><link href="https://zaurnasibov.com/posts/2010/04/28/why_opera.html" rel="alternate"/><published>2010-04-28T12:00:00+03:00</published><updated>2010-04-28T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-04-28:/posts/2010/04/28/why_opera.html</id><summary type="html">&lt;p class="first last"&gt;There are so many browsers out there! Internet Explorer, Chrome, Firefox, Safari - are the major players on the market. But hey, there is another major and one of the oldest browsers in the world: Opera. You might have heard lots of rumours about it. Maybe even used it. Or maybe you belong to a small group of people, who actually use this browser everyday. Would you like to know, why I've been using Opera for 10 years?&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="a-real-hacker"&gt;
&lt;h2&gt;A real hacker?&lt;/h2&gt;
&lt;p&gt;Opera is my major browser since version 5.02. I discovered it in &amp;quot;Хакер&amp;quot;
(russian word for &amp;quot;Hacker&amp;quot;) monthly magazine. It was described as an innovative
browser with a &amp;quot;jet engine&amp;quot; inside. With the &amp;quot;A real hacker should use
Opera!&amp;quot; motto I launched the program... And for ten years Opera never stopped
surprising me.&lt;/p&gt;
&lt;p&gt;You can find lots of &amp;quot;Opera vs. Firefox&amp;quot; or &amp;quot;Opera vs. Chrome&amp;quot; or &amp;quot;Opera vs.
Something-something-something&amp;quot;. Most of those articles will lead you to a
&amp;quot;speed test&amp;quot; results. Do you really care, if your browser runs a benchmark
in 10.1 seconds, with top competitor running it in 9.812 s.? I don't. What
I really care of is how the browser is easy-to-use, is compatible with
standards and well.. how good it serves my needs.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="features"&gt;
&lt;h2&gt;Features?&lt;/h2&gt;
&lt;p&gt;Even if you're an experienced user, you may find lots of features you've
never heard about. For example, do you know that Opera has a &amp;quot;Show&amp;quot; mode?
No a common feature though.&lt;/p&gt;
&lt;p&gt;What about the common features?&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Trash bin&lt;/strong&gt; for closed tabs. If you close a tab accidentally, &lt;tt class="docutils literal"&gt;Ctrl + z&lt;/tt&gt;
restores it immediately.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Navigation&lt;/strong&gt; via mouse or keyboard is very fast in Opera. There are
&lt;em&gt;mouse gestures&lt;/em&gt;, back-and-forward clicks (press left button while holding
right button to navigate back), Wand password manager (just press
&lt;tt class="docutils literal"&gt;Ctrl + Enter&lt;/tt&gt; or the &lt;cite&gt;Wand&lt;/cite&gt; button on toolbar to login automatically),
keyboard navigation (e.g. &lt;tt class="docutils literal"&gt;Shift + arrow keys&lt;/tt&gt;), middle-click panning..
have I forgotten something?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zooming&lt;/strong&gt; is another great usability feature. A user can combine it with
the &lt;cite&gt;Fit to width&lt;/cite&gt; feature - that allows zooming into page and being able
to navigate without using horizontal scroll bar at all!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Search engine customization&lt;/strong&gt; allows one to create a &amp;quot;search engine&amp;quot; from
any text box on any website. For example, I often use Google translate's
Finnish-to-English page. With custom &amp;quot;search engine&amp;quot; in Opera , all I have
to do is to type &lt;tt class="docutils literal"&gt;&amp;quot;gfi [word or phrase]&amp;quot;&lt;/tt&gt; in address bar and press
&amp;quot;Enter&amp;quot; - Opera will take me to a page with translated text.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Opera Unite&lt;/strong&gt; is a technology that turns a browser into a web server.
One can share files, music, pictures, serve static html pages, create
chatrooms.. you name it!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a very short incomplete list and there are lots and lots of other
great features. But I'm sure you get the idea :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="portability"&gt;
&lt;h2&gt;Portability?&lt;/h2&gt;
&lt;p&gt;You see, with Opera you can get it's all wonderful features in one place,
without messing with add-ons, extensions, plug-ins etc. I get very annoyed
when I have to use a computer at the university with a &amp;quot;blank&amp;quot; Firefox on it.
&amp;quot;Blank&amp;quot; means - no particular extensions that could ease user's work. I can
have a perfectly customized Firefox on my own computer.. but as soon as I
reach a &amp;quot;blank&amp;quot; installation or even another persons customized environment
- I fail.&lt;/p&gt;
&lt;p&gt;Sorry for mentioning Firefox, but I wanted to explain, why &amp;quot;add-ons&amp;quot; approach
might not work for a person who seeks a complete solution. I respect Mozilla
foundation and understand why the &amp;quot;add-ons&amp;quot; way was chosen. Moreover,
this way has proved it's consistency and our days Firefox has a much bigger
market share than Opera.&lt;/p&gt;
&lt;p&gt;But let's continue with Opera. Opera is truly cross-platform software. Opera
remains the same on Linux, Windows, MacOS, *BSD. A user gets the same features
on all platforms!. Does your mobile phone supports Java? There is Opera Mini
to serve you. Here comes another feature that was introduced in Opera 9.5
(back in 2007): synchronization. You add a bookmark in your mobile phone and
it appears in your desktop browser. You type an address in Opera's address bar
at work, and then get a clue from the browser's &amp;quot;typed addresses history&amp;quot;
at home. Will you agree that all this makes Opera extremely portable?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="give-it-a-try"&gt;
&lt;h2&gt;Give it a try!&lt;/h2&gt;
&lt;p&gt;I hope that I convinced you to give &lt;a class="reference external" href="http://my.opera.com/community/download.pl?ref=BasicWolf&amp;amp;p=opera_desktop"&gt;Opera&lt;/a&gt; another try :) Enjoy!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Opera"/></entry><entry><title>Inside Python subprocess communication</title><link href="https://zaurnasibov.com/posts/2010/04/24/inside_python_subprocess_communication.html" rel="alternate"/><published>2010-04-24T12:00:00+03:00</published><updated>2010-04-24T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-04-24:/posts/2010/04/24/inside_python_subprocess_communication.html</id><summary type="html">&lt;p class="first last"&gt;Sometimes, it's really hard to understand what happens inside a function or even a whole module of Python's Standard library. For example, the subprocess module contains a very tricky Popep class. I tried to use the the module to communicate with a MATLAB subprocess shell (e.g. send MATLAB commands to subprocess and read the output). Unfortunately I failed and was just able to pass a MATLAB script via command-line arguments. Yet, I learnt much about the &lt;tt class="docutils literal"&gt;Popen.communicate()&lt;/tt&gt; method and I'd like to share this knowledge with you.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="before-we-begin"&gt;
&lt;h2&gt;Before we begin&lt;/h2&gt;
&lt;p&gt;I love Python and try using the latest versions when possible. But this
article is about the subprocess module in Python 2.6. Is there a good
reason for that? For starters, you can find this comment in Python 3.1's
subprocess module:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# XXX Rewrite these to use non-blocking I/O on the&lt;/span&gt;
&lt;span class="c1"&gt;# file objects; they are no longer using C stdio!&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Then, there is a pending &lt;a class="reference external" href="http://www.python.org/dev/peps/pep-3145"&gt;Asynchronous I/O For subprocess. Popen PEP-3145.&lt;/a&gt; Last, but not least, a&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;em&gt;temporary moratorium (suspension) of all changes to the Python language
syntax, semantics, and built-ins for a period of at least two years from
the release of Python 3.1&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;was proposed and accepted in PEP 3003. Yet,&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;em&gt;..As the standard library is not directly tied to the language definition
it is not covered by this moratorium.&lt;/em&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="a-simple-experiment"&gt;
&lt;h2&gt;A simple experiment&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-l&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This one is really easy: the &lt;tt class="docutils literal"&gt;ls&lt;/tt&gt; command with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-l&lt;/span&gt;&lt;/tt&gt; switch is
executed, the root is set as a current working directory and a pipe is
created to get the data written by ls to &lt;tt class="docutils literal"&gt;stdout&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Why use communicate? Why not write the data directly to &lt;tt class="docutils literal"&gt;Popen.stdin&lt;/tt&gt;
and read from &lt;tt class="docutils literal"&gt;Popen.stdout&lt;/tt&gt;?&lt;/p&gt;
&lt;p&gt;The official documentation says:&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
Use &lt;tt class="docutils literal"&gt;communicate()&lt;/tt&gt; rather than
&lt;tt class="docutils literal"&gt;Popen.stdin.write&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;Popen.stdout.read&lt;/tt&gt; or &lt;tt class="docutils literal"&gt;Popen.stderr.read&lt;/tt&gt;
to avoid deadlocks due to any of the other OS pipe buffers filling up
and blocking the child process.&lt;/blockquote&gt;
&lt;p&gt;Let's try &lt;tt class="docutils literal"&gt;communicate()&lt;/tt&gt; with a long-term shell process:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;subprocess&lt;/span&gt;

&lt;span class="n"&gt;proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bash&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;communicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ls -l&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;With successful first communicate() call, you'll receive
&lt;tt class="docutils literal"&gt;ValueError: I/O operation on closed file&lt;/tt&gt; trying communicate the second
time.&lt;/p&gt;
&lt;p&gt;Would you like to know, why an error is raised? It's time to dive deeper
into the code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="inside-popen-communicate"&gt;
&lt;h2&gt;Inside Popen.communicate()&lt;/h2&gt;
&lt;p&gt;You can find the original and complete code of subprocess module in e.g.
&lt;tt class="docutils literal"&gt;/usr/lib/python2.6/subprocess.py&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note the comments!&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;communicate&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="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Interact with process: Send data to stdin.  Read data from&lt;/span&gt;
&lt;span class="sd"&gt;   stdout and stderr, until end-of-file is reached.  Wait for&lt;/span&gt;
&lt;span class="sd"&gt;   process to terminate.  The optional input argument should be a&lt;/span&gt;
&lt;span class="sd"&gt;   string to be sent to the child process, or None, if no data&lt;/span&gt;
&lt;span class="sd"&gt;   should be sent to the child.&lt;/span&gt;

&lt;span class="sd"&gt;   communicate() returns a tuple (stdout, stderr).&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

   &lt;span class="c1"&gt;# Optimization: If we are only using one pipe, or no pipe at&lt;/span&gt;
   &lt;span class="c1"&gt;# all, using select() or threads is unnecessary.&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
      &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="c1"&gt;# This happens in the experiment we ran above&lt;/span&gt;
         &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

         &lt;span class="c1"&gt;# Note, stdout is closed!&lt;/span&gt;
         &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
         &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
         &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="c1"&gt;# Waiting until process terminates!&lt;/span&gt;
      &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;# The most interesting case, two or more pipes opened&lt;/span&gt;
   &lt;span class="c1"&gt;# Remember, self is an instance of subprocess.Popen class&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_communicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Python was made to be cross-platform. On the other hand Python is generally
used on POSIX-compatible operating systems. Let's skip the &lt;tt class="docutils literal"&gt;if mswindows:&lt;/tt&gt;
part and get to the POSIX methods block:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_communicate&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="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# there is a historical reason calling this variables &amp;quot;sets&amp;quot;&lt;/span&gt;
    &lt;span class="c1"&gt;# see select.select() (below)&lt;/span&gt;
    &lt;span class="n"&gt;read_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;write_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# returned variables&lt;/span&gt;
    &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="c1"&gt;# the tricky part starts right here&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Flush stdio buffer.  This might block (!), if the user has&lt;/span&gt;
        &lt;span class="c1"&gt;# been writing to .stdin in an uncontrolled fashion.&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Data to be sent to the process through the pipe&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;write_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;read_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;read_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;input_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;This part was not hard at all.
It'll be a little bit harder in the next block: please read the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;select.select()``[1]_&lt;/span&gt; documentation if you're not familiar with the
``select()&lt;/tt&gt; system call.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;#...&lt;/span&gt;
&lt;span class="c1"&gt;# while read_set contains self.stdout&lt;/span&gt;
&lt;span class="c1"&gt;# or write_set contains self.stdin&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;read_set&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;write_set&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="c1"&gt;# man select&lt;/span&gt;
       &lt;span class="c1"&gt;# .. select() allows a program to monitor multiple file descriptors,&lt;/span&gt;
       &lt;span class="c1"&gt;# waiting until one or more of the file descriptors become &amp;quot;ready&amp;quot;&lt;/span&gt;
       &lt;span class="c1"&gt;# for some class of I/O operation (e.g., input possible).&lt;/span&gt;
       &lt;span class="c1"&gt;# A file descriptor is  considered ready if it is possible to perform&lt;/span&gt;
       &lt;span class="c1"&gt;# the corresponding I/O operation (e.g., read) without blocking&lt;/span&gt;
       &lt;span class="n"&gt;rlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;wlist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xlist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

       &lt;span class="c1"&gt;# EINTR means &amp;quot;This call did not succeed because it was interrupted.&lt;/span&gt;
       &lt;span class="c1"&gt;# However, if you try again, it will probably work.&amp;quot;&lt;/span&gt;
       &lt;span class="c1"&gt;# In other words, EINTR is not a fatal error, it just means&lt;/span&gt;
       &lt;span class="c1"&gt;# you should retry whatever you were attempting.&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;errno&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EINTR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="k"&gt;continue&lt;/span&gt;
       &lt;span class="k"&gt;raise&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;wlist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="c1"&gt;# When select has indicated that the file is writable,&lt;/span&gt;
       &lt;span class="c1"&gt;# we can write up to PIPE_BUF bytes without risk&lt;/span&gt;
       &lt;span class="c1"&gt;# blocking.  POSIX defines PIPE_BUF &amp;gt;= 512&lt;/span&gt;
       &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input_offset&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;input_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="n"&gt;bytes_written&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="n"&gt;input_offset&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;bytes_written&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;input_offset&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
          &lt;span class="c1"&gt;# stdin is closed! It&amp;#39;s not possible communicate(input) any more.&lt;/span&gt;
          &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
          &lt;span class="n"&gt;write_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# write_set is empty now&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rlist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1024&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;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;read_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rlist&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fileno&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;1024&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;data&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="n"&gt;read_set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Note, that &lt;tt class="docutils literal"&gt;os.write()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;os.read()&lt;/tt&gt; functions are being used.
This functions are intended for low-level I/O. If the end of the file
referred to by file descriptor (e.g. &lt;tt class="docutils literal"&gt;self.stdout.fileno()&lt;/tt&gt;) has been
reached, an empty string is returned (the &lt;tt class="docutils literal"&gt;if data == &amp;quot;&amp;quot;:&lt;/tt&gt; conditions).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;#...&lt;/span&gt;
&lt;span class="c1"&gt;# The while read_set or write_set: loop ends here&lt;/span&gt;
&lt;span class="c1"&gt;# All data exchanged.  Translate lists into strings.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&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;stdout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# (stdout) is a list&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="o"&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;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Translate newlines, if requested.  We cannot let the file&lt;/span&gt;
&lt;span class="c1"&gt;# object do the translation: It is based on stdio, which is&lt;/span&gt;
&lt;span class="c1"&gt;# impossible to combine with select (unless forcing no&lt;/span&gt;
&lt;span class="c1"&gt;# buffering).&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;universal_newlines&lt;/span&gt; &lt;span class="ow"&gt;and&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;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;newlines&amp;#39;&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;stdout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_translate_newlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdout&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;stderr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
       &lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_translate_newlines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# wait until process terminates&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;If Python was built with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--with-universal-newlines&lt;/span&gt;&lt;/tt&gt; option in
configure (the default), the &lt;tt class="docutils literal"&gt;file.newlines&lt;/tt&gt; read-only attribute exists,
and for files opened in universal newline read mode it keeps track of the
types of newlines encountered while reading the file. The
&lt;tt class="docutils literal"&gt;_translate_newlines()&lt;/tt&gt; method just replaces the Windows-style
(&lt;tt class="docutils literal"&gt;\r\n&lt;/tt&gt;) and Mac-style (&lt;tt class="docutils literal"&gt;\r&lt;/tt&gt;) newlines with &lt;tt class="docutils literal"&gt;\n&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The last pieces of the puzzle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;
&lt;span class="normal"&gt;9&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;wait&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="w"&gt;    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Wait for child process to terminate.  Returns returncode&lt;/span&gt;
&lt;span class="sd"&gt;    attribute.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Try calling a function os.waitpid(self.pid, 0)&lt;/span&gt;
        &lt;span class="c1"&gt;# Ignore Interrupted System Call (errno.EINTR) errors&lt;/span&gt;
        &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_eintr_retry_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;waitpid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_handle_exitstatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[1]&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://docs.python.org/library/select.html#select.select"&gt;http://docs.python.org/library/select.html#select.select&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="Python"/></entry><entry><title>A very long nightmare</title><link href="https://zaurnasibov.com/posts/2010/04/01/a_very_long_nightmare.html" rel="alternate"/><published>2010-04-01T12:00:00+03:00</published><updated>2010-04-01T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-04-01:/posts/2010/04/01/a_very_long_nightmare.html</id><summary type="html">&lt;p class="first last"&gt;The worst thing has happened: I have an unexpected drive failure. That's how my Easter has started :(&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Few tools I can use right now:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Ubuntu 8.10 Live CD (without Ext4 suppor!)&lt;/li&gt;
&lt;li&gt;A usb flash drive&lt;/li&gt;
&lt;li&gt;A two month-old backup (agh!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm writing this post in Ubuntu loaded from LiveCD. Right now, I'm downloading
Ubuntu 10.04 and RIPLinux distribution. I hope everything will be fine :)&lt;/p&gt;
&lt;div class="section" id="update-3-00-am"&gt;
&lt;h2&gt;Update&amp;#64;3.00 AM&lt;/h2&gt;
&lt;p&gt;Some files are corrupted, but I was able to backup projects and master thesis
materials. Now, backing up thunderbird directory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="update-6-55-am"&gt;
&lt;h2&gt;Update&amp;#64;6.55 AM&lt;/h2&gt;
&lt;p&gt;There are more than 2 millions bad sectors on the drive. I'm lucky to have
two external USB SATA drives. I hope that the only thing I've missed this
night - were sweet dreams :)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="update-8-39-am"&gt;
&lt;h2&gt;Update&amp;#64;8.39 AM&lt;/h2&gt;
&lt;p&gt;Ubuntu 10.04 Beta is installed and updated. Too tired to write how BAD I
felt about it. Looks like I have to move on. Long ago, when I lived and
studied in Saint Petersburg, me and my roommate Vova had frequent
conversations about Linux world. Ubuntu was new, still, as Vova said,
&amp;quot;There is always will be Debian&amp;quot;.
I'm downloading Debian Testing right now. Thank you for everything
you've taught me, Ubuntu!&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="update-21-00"&gt;
&lt;h2&gt;Update&amp;#64;21.00&lt;/h2&gt;
&lt;p&gt;What the HELL! I never thought that Debian will cause so many problems.
First, there is no iwlagn4945 firmware in first installation CD. And I
don't have an Ethernet cable to connect and download everything required
for normal network support. Agh. I'm getting back to Ubuntu :)&lt;/p&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Linux"/><category term="Ubuntu"/><category term="Debian"/><category term="disk"/><category term="fail"/></entry><entry><title>Python classes: Dynamic properties</title><link href="https://zaurnasibov.com/posts/2010/03/10/python_classes_dynamic_properties.html" rel="alternate"/><published>2010-03-10T12:00:00+02:00</published><updated>2010-03-10T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2010-03-10:/posts/2010/03/10/python_classes_dynamic_properties.html</id><summary type="html">&lt;p class="first last"&gt;Python never stops surprising me. While doing my master IT project, I was looking for a way to add dynamic properties to classes (we're speaking of new-style classes of course!). I did a little research and here are the results...&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="i-love-python-3"&gt;
&lt;h2&gt;I love Python 3&lt;/h2&gt;
&lt;p&gt;Even Python 2.x is still used everywhere, it is time to move to Python 3.
I made the code fully Python2.6 - compatible, but if you'd like to have a
nice output of print(..) function please use the&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;__future__&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;print_function&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;statement.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-simple-class"&gt;
&lt;h2&gt;A simple class&lt;/h2&gt;
&lt;p&gt;This is a simple class with one property:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Man&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;name&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="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt;

    &lt;span class="nd"&gt;@name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setter&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;name&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;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Man&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Alex Black&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Kyra Brown&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The output is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;Alex Black
Kyra Brown
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;We keep the local values in attributes that start with the underscore,
e.g. self._name. Usually this is a way I separate &amp;quot;private&amp;quot; and &amp;quot;public&amp;quot;
members of a class/object &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt; (of course this &amp;quot;private&amp;quot; members remain
&amp;quot;public&amp;quot;).&lt;/p&gt;
&lt;p&gt;This code does the same as the code above:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Man&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_name_get&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="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&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="s1"&gt;&amp;#39;_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_name_set&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;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&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="s1"&gt;&amp;#39;_name&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name_get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name_set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;There are two core changes:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;_name&lt;/tt&gt; attribute of an object is read and set by the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;getattr(..)&lt;/span&gt;&lt;/tt&gt;
and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;setattr(..)&lt;/span&gt;&lt;/tt&gt; functions.&lt;/li&gt;
&lt;li&gt;The &lt;tt class="docutils literal"&gt;&amp;#64;property&lt;/tt&gt; decorator is replaced by the built-in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;property(...)&lt;/span&gt;&lt;/tt&gt;
function &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; (which is actually &amp;quot;behind&amp;quot; that decorator).&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="dynamic-properties-class"&gt;
&lt;h2&gt;Dynamic properties class&lt;/h2&gt;
&lt;p&gt;Finally, let's write a class called &amp;quot;Properties&amp;quot; that will allow adding dynamic
properties. The properties will require local (&amp;quot;private&amp;quot;) fields. We can use
the same scheme as above, e.g. for property name, the private member of a
class is &lt;tt class="docutils literal"&gt;_name&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add_property&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# create local fget and fset functions&lt;/span&gt;
        &lt;span class="n"&gt;fget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# add property to self&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="c1"&gt;# add corresponding local variable&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_property&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_get_property&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;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The trick in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;add_property(..)&lt;/span&gt;&lt;/tt&gt; is that we create two lambda objects (those
could also be anonymous functions) which use the &lt;tt class="docutils literal"&gt;self._get_property&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;self._set_property&lt;/tt&gt; methods with particular value of name argument.&lt;/p&gt;
&lt;p&gt;Let's play with this class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;noname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;speed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Alex Black&amp;#39;&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The output is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;noname 50
Alex Black 100
Alex Black 100
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="a-practical-usage"&gt;
&lt;h2&gt;A practical usage&lt;/h2&gt;
&lt;p&gt;After all, what is a practical usage of dynamic properties? I'm sure you
may have thought of that if you're reading this post now :) Here is a small
example of a class which is able to &amp;quot;lock&amp;quot; the properties' setters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;PropertiesWithLock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&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;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&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;lock&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;add_property&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;fget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_get_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&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;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_set_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__class__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fset&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nb"&gt;setattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_set_property&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&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="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nb"&gt;setattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
             &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Cannot change &amp;quot;&lt;/span&gt;&lt;span class="si"&gt;{0}&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot;: properties are locked&amp;#39;&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;_get_property&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;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;getattr&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="s1"&gt;&amp;#39;_&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And the usage:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PropertiesWithLock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;user&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;noname&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;speed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;noname&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;

&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a user&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;

&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;po&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a user&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Cannot&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;locked&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://docs.python.org/reference/lexical_analysis.html#reserved-classes-of-identifiers"&gt;Reserved classes of identifiers&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://docs.python.org/library/functions.html#property"&gt;property([fget[, fset[, fdel[, doc]]]])&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="Python"/></entry><entry><title>Back to life</title><link href="https://zaurnasibov.com/posts/2009/08/19/back-to-life.html" rel="alternate"/><published>2009-08-19T12:00:00+03:00</published><updated>2009-08-19T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-08-19:/posts/2009/08/19/back-to-life.html</id><summary type="html">&lt;p class="first last"&gt;There were no blog updates during 8 month! But I am finally back to life!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Lots of things happened. I have recently finished my IT Project (as a part
of my studies).&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;VADpy is a universal, modular, easy-to-run and easy-to-extend Voice
Activity Detection algorithms testing framework that puts different
speech/sound databases, VADs, error metrics and performance reports
in one place. VADpy saves developers time by providing convinient MATLAB
interface for MATLAB-based VADs. A powerful modular architecture lets
developers integrate any kind of file databases and VADs into the framework.
The Python programming language provides convinient environment to develop
input, error metric and output modules.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;VADpy adtext.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I learned lots of new things about Python while working on this project.
I hope to share this knowledge in my blog.&lt;/p&gt;
&lt;p&gt;Also, I got rid out of static html, now the blog runs on Django. The
&amp;quot;engine&amp;quot; is still in development (comments with captcha are on their way)
yet, the blog is fully-functional and you're welcome to read it.&lt;/p&gt;
</content><category term="Articles"/><category term="life"/></entry><entry><title>Beginner's guide to creating a GNOME 2 applet with Python (Part II)</title><link href="https://zaurnasibov.com/posts/2009/08/19/gnome_applet_with_python_part_2.html" rel="alternate"/><published>2009-08-19T12:00:00+03:00</published><updated>2009-08-19T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-08-19:/posts/2009/08/19/gnome_applet_with_python_part_2.html</id><summary type="html">&lt;p class="first last"&gt;It's been a while since I wrote the first part of this guide. I'm happy to introduce you the second part of the tutorial. This part continues the story about applet-only techniques. Even if you're skilled in PyGTK, you are adviced to read this part.&lt;/p&gt;
</summary><content type="html">&lt;div class="section" id="part-ii-gnome-applets-and-pygtk"&gt;
&lt;h2&gt;Part II: GNOME applets and PyGTK&lt;/h2&gt;
&lt;div class="section" id="before-we-begin"&gt;
&lt;h3&gt;Before we begin...&lt;/h3&gt;
&lt;p&gt;If you have read part I of the tutorial, and have a test applet running
in both &amp;quot;panel&amp;quot; and &amp;quot;debug&amp;quot; mode, you would have no problems running all
the code described below. All terms described in part I, keep their meanings
here so, if you have not read the article, you can do it now.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="launching-an-applet"&gt;
&lt;h3&gt;1. Launching an applet&lt;/h3&gt;
&lt;p&gt;Generally, a GNOME applet could be treated as an application &amp;quot;attached&amp;quot; to
the panel through Bonobo component model system &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-1"&gt;[2]&lt;/a&gt;. We can launch the
sample applet in a standard GNOME window with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-d&lt;/span&gt;&lt;/tt&gt; key &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-2"&gt;[1]&lt;/a&gt;. Yet,
for example creating and attaching a menu to an applet is not the same
task of creating a menu for a windowed application. Or, an applet will
always be vertically-oriented&amp;quot; in debug-mode. So, this time the applet
will be added to a panel during all test-runs.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;If the sample applet doesn't appear on a panel, it means, that
something went wrong (a possible bug in a script). Try launching the
applet in debug mode to see the output and catch possible bugs.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="popup-context-menu"&gt;
&lt;h3&gt;2. Popup Context Menu&lt;/h3&gt;
&lt;p&gt;Every applet has a basic context popup-menu with three (at least in GNOME
v2.26) items:&lt;/p&gt;
&lt;img alt="applet sample" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_applet_sample.png" /&gt;
&lt;p&gt;According to the GNOME documentation library &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;, the only way to extend
this menu is to call the following function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;panel_applet_setup_menu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PanelApplet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gchar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BonoboUIVerb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;verb_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The corresponding method in Python is Applet object's
&lt;tt class="docutils literal"&gt;setup_menu(xml, verbs, user_data)&lt;/tt&gt; method.&lt;/p&gt;
&lt;p&gt;The required xml string is in a very easy-to-understand XML format:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;popup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;button3&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;menuitem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ItemPreferences&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Preferences&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_Preferences&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;pixtype=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stock&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;pixname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;gtk-preferences&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;separator/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;submenu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Submenu&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;_label=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Su_bmenu&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;menuitem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ItemAbout&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;verb=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;About&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;_About&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;pixtype=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stock&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="na"&gt;pixname=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;gtk-about&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/submenu&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/popup&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The example above creates a menu of two items, a separator between them
and a single sub-item:&lt;/p&gt;
&lt;img alt="applet menu" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_menu.png" /&gt;
&lt;p&gt;As you can see, the Preferences and About icons are set from the current
environment's theme.
So, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pixtype=&amp;quot;stock&amp;quot;&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pixname=&amp;quot;gtk-about&amp;quot;&lt;/span&gt;&lt;/tt&gt; attributes mean that
an icon from GTK stock collection named &amp;quot;gtk-about&amp;quot; &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-4"&gt;[4]&lt;/a&gt; will appear in
a menu item.
The name and label attributes define menuitem object's name and label
properties. The underscore (&lt;tt class="docutils literal"&gt;_&lt;/tt&gt;) character defines a shortcut to a menu.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;verb&lt;/strong&gt; attribute is crucial for each &lt;strong&gt;menuitem&lt;/strong&gt; node. The name of
each verb links a menuitem and a callback function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;verbs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;About&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show_about&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Preferences&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show_preferences&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;To link the menus and the verbs list to an applet, the &lt;tt class="docutils literal"&gt;setup_menu()&lt;/tt&gt;
method is called:1&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;strong&gt;None&lt;/strong&gt; is a &amp;quot;user data&amp;quot; (could be any python data object or None).&lt;/p&gt;
&lt;p&gt;Finally, all snippets described above, plus callback functions will look
as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&amp;lt;popup name=&amp;quot;button3&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;menuitem name=&amp;quot;ItemPreferences&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              verb=&amp;quot;Preferences&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              label=&amp;quot;_Preferences&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              pixtype=&amp;quot;stock&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              pixname=&amp;quot;gtk-preferences&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;separator/&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;submenu name=&amp;quot;Submenu&amp;quot; _label=&amp;quot;Su_bmenu&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;menuitem name=&amp;quot;ItemAbout&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              verb=&amp;quot;About&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              label=&amp;quot;_About&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              pixtype=&amp;quot;stock&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;              pixname=&amp;quot;gtk-about&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;/submenu&amp;gt;&lt;/span&gt;
&lt;span class="s2"&gt;          &amp;lt;/popup&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

   &lt;span class="n"&gt;verbs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;About&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show_about&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Preferences&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;show_preferences&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
   &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;show_about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;show_preferences&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gnome_applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;create_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gnome_applet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
   &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Try launching the applet in &lt;strong&gt;debug&lt;/strong&gt; mode, and printing out the
&lt;tt class="docutils literal"&gt;*arguments&lt;/tt&gt; list in &lt;tt class="docutils literal"&gt;show_about()&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;show_preferences()&lt;/tt&gt; functions.&lt;/p&gt;
&lt;p&gt;The result should be similar to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(&amp;lt;bonobo.ui.Component object at 0x963f5cc (BonoboUIComponent at 0x969dac0)&amp;gt;, &amp;#39;About&amp;#39;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Also try changing the None argument in &lt;tt class="docutils literal"&gt;setup_menu()&lt;/tt&gt; method to e.g.
&lt;tt class="docutils literal"&gt;'Hello!'&lt;/tt&gt; string and then printing out the &lt;tt class="docutils literal"&gt;*arguments&lt;/tt&gt; list one more
time. This time, the result should look like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;(&amp;lt;bonobo.ui.Component object at 0x963f5cc (BonoboUIComponent at 0x969dac0)&amp;gt;, &amp;#39;About&amp;#39;, &amp;#39;Hello!&amp;#39;)
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now, you can change the callbacks' definitions&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;show_about&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;show_about&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;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;which slightly clarifies the code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="applet-s-orientation"&gt;
&lt;h3&gt;3.1 Applet's orientation&lt;/h3&gt;
&lt;p&gt;An applet could be set up both on a horizontal or vertical panel. This
should be taken into account before creating the visual elements of an
applet. Also an applet's orientation could be changed by user (dragging
an applet from a horizontal panel to vertical panel), in this case a
callback for the change-orient signal should be created &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-5"&gt;[5]&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;change_orientation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;change-orient&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;change_orientation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The code below demonstrates how change-orient signal could be used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# initialize an orientation-dependent label&lt;/span&gt;
    &lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_orient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ORIENT_UP&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt;
        &lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ORIENT_DOWN&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Vertical&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Horizontal&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# label is the user data&lt;/span&gt;
    &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;change-orient&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;change_orientation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;change_orientation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_orient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ORIENT_UP&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt;
        &lt;span class="n"&gt;orientation&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ORIENT_DOWN&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Vertical&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Horizontal&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The applet was added to a vertical panel:&lt;/p&gt;
&lt;img alt="vertical applet" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_vertical.png" /&gt;
&lt;p&gt;Then, dragged to a auto-hidden horizontal one:&lt;/p&gt;
&lt;img alt="horizontal applet" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_horizontal.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="applet-s-background"&gt;
&lt;h3&gt;3.2 Applet's background&lt;/h3&gt;
&lt;p&gt;The GNOME panel has three background options:&lt;/p&gt;
&lt;img alt="applet on a panel" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_panel.png" /&gt;
&lt;p&gt;And an applet can detect these options' changes via the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;change-background&lt;/span&gt;&lt;/tt&gt;
signal &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-6"&gt;[6]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But in practical situations, an applet doesn't respond to the panel's
background changes. What really matters is an applet's background
transparency. This is where the power of GNU helps: the sources of GNOME
trash applet contain a &amp;quot;hack&amp;quot; line of code that makes an applet transparent.
In Python it is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_background_widget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# /* enable transparency hack */&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Now, the applet should look like this:&lt;/p&gt;
&lt;img alt="transparent applet" class="align-center" src="https://zaurnasibov.com/articles/2009_08_19_gnome_applet_with_python_part_2/gnomeapplet_2_transparency.png" /&gt;
&lt;p&gt;That's it! This is the end of the second part of the tutorial. There is
not much left to say about the applet techniques. But there is much to
learn about PyGTK (creating dialogs, different widgets, signals, etc.).
A great tutorial is available at the official site &lt;a class="reference external" href="http://www.pygtk.org"&gt;http://www.pygtk.org&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;Beginner's guide to creating a GNOME applet with Python (Part I)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Bonobo_(component_model)"&gt;Bonobo component model&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://developer.gnome.org/panel-applet/"&gt;The PanelApplet object&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://developer.gnome.org/gtk3/stable/gtk3-Stock-Items.html"&gt;GTK stock items&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-5"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.pygtk.org/articles/applets_arturogf/x186.html"&gt;www.pygtk.org - GNOME applet with python&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-6"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="https://developer.gnome.org/panel-applet/2.32/panel-applet-panel-applet.html#PanelApplet-change-background"&gt;The &amp;quot;change-background&amp;quot; signal&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="Python"/><category term="Gnome"/></entry><entry><title>Big and Little endianness quest</title><link href="https://zaurnasibov.com/posts/2009/08/01/big_little_endian_quest.html" rel="alternate"/><published>2009-08-01T12:00:00+03:00</published><updated>2009-08-01T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-08-01:/posts/2009/08/01/big_little_endian_quest.html</id><summary type="html">&lt;p class="first last"&gt;Sometimes the bugs in programs do not depend on a programmer. For example, when a programmer expects a certain result from a built-in function, that would be the last place to check for bugs. But sometimes weird stuff happens, and it also happened to me.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I was working with G.729 Annex B 's &lt;cite&gt;source code
&amp;lt;http://www.itu.int/rec/T-REC-G.729/en&amp;gt;&lt;/cite&gt; to extract the codec's Voice
Activity Detector (VAD).&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;Voice activity detection is a technique used in speech processing
wherein the presence or absence of human speech is detected in regions
of audio (which may also contain music, noise, or other sound).&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Wikipedia &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The result of my work was a tool that produced &lt;tt class="docutils literal"&gt;0&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;1&lt;/tt&gt; binary
output for a speech and non-speech 10ms-long sections of a sound file
with sampling frequency of 8000 Hz and 16 bits PCM data.&lt;/p&gt;
&lt;p&gt;The Aurora speech recognition experimental framework &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; data was used to
test the program. That was the point where the problems began.&lt;/p&gt;
&lt;p&gt;The VAD was not working. Almost every part of every file was marked as
&amp;quot;speech&amp;quot;. But that was not true! And the G729 Annex B VAD could not work
so awful. Where was the problem?&lt;/p&gt;
&lt;p&gt;The original G.729 reads the input file as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_speech&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Word16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L_FRAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;f_speech&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L_FRAME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Where &lt;tt class="docutils literal"&gt;new_speech&lt;/tt&gt; is a &lt;tt class="docutils literal"&gt;L_FRAME&lt;/tt&gt;-long array of &lt;tt class="docutils literal"&gt;Word16&lt;/tt&gt; (short)
elements. Then the &lt;tt class="docutils literal"&gt;new_speech&lt;/tt&gt; data is pre-processed, passed through
and compressed via the codec. I removed the compression part and the code
looked like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;Pre_Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_speech&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;L_FRAME&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Vad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Coder_ld8a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Probably the error was in the &lt;tt class="docutils literal"&gt;Coder_ld8a()&lt;/tt&gt; function. But how could
it be? I just removed the compression stuff, and added&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;return 1 for speech sections&lt;/li&gt;
&lt;li&gt;return 0 for non-speech sections&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I could have spent a lot of time hunting the &amp;quot;ghost&amp;quot; bug, if my supervisor
Rahim Saedi didn't ask, whether the files were read correctly.
OMG! A possible bug error in &lt;tt class="docutils literal"&gt;fread()&lt;/tt&gt; function?&lt;/p&gt;
&lt;p&gt;I checked the values of the new_speech array for a random file from the
Aurora database and found something weird: the values sequence was
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-1&lt;/span&gt; &lt;span class="pre"&gt;-1&lt;/span&gt; 0 0 256 &lt;span class="pre"&gt;-1&lt;/span&gt; 0 0 0 256 ...&lt;/tt&gt; Something clicked in my mind.&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;In computing, endianness is the byte (and sometimes bit) ordering used
to represent some kind of data. Most modern computer processors agree
on bit ordering &amp;quot;inside&amp;quot; individual bytes (this was not always the case).
This means that any single-byte value will be read the same on almost
any computer one may send it to.&lt;/p&gt;
&lt;p&gt;Integers are usually stored as sequences of bytes, so that the encoded
value can be obtained by simple concatenation. The two most common of
them are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;increasing numeric significance with increasing memory addresses or
increasing time, known as &lt;em&gt;little-endian&lt;/em&gt;, and&lt;/li&gt;
&lt;li&gt;its opposite, most-significant byte first, called &lt;em&gt;big-endian&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Well known processor architectures that use the little-endian format
include x86.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Wikipedia &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I was using a x86 processor that uses the &lt;em&gt;little-endian&lt;/em&gt; format, trying to
read a file that contained 16-bit integers in &lt;em&gt;big-endian&lt;/em&gt; format!&lt;/p&gt;
&lt;p&gt;It's easier to imagine what happened, with binary representation of the
decimal &lt;tt class="docutils literal"&gt;1&lt;/tt&gt; in 16-bit big-endian and little-endian formats:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;00000000 00000001&lt;/tt&gt; - Big endian&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;00000001 00000000&lt;/tt&gt; - Little endian&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And vice-versa the decimal &lt;tt class="docutils literal"&gt;256&lt;/tt&gt; is:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;00000001 00000000&lt;/tt&gt; - Big endian&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;00000000 00000001&lt;/tt&gt; - Little endian&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now you can see: the program read the big-endian data and interpreted it
as little-endian. So, all values were actually multiplied by 256!&lt;/p&gt;
&lt;p&gt;Finally, a small piece of code helped to eliminate the problem:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reverseShort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;short&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Voice_activity_detection"&gt;http://en.wikipedia.org/wiki/Voice_activity_detection&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://aurora.hsnr.de/index.html"&gt;http://aurora.hsnr.de/index.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-3"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Endianness"&gt;http://en.wikipedia.org/wiki/Endianness&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="programming"/><category term="G.729"/><category term="C"/><category term="VAD"/></entry><entry><title>Emacs, LaTeX and pdf viewer</title><link href="https://zaurnasibov.com/posts/2009/04/14/emacs_latex_and_pdf_viewer.html" rel="alternate"/><published>2009-04-14T12:00:00+03:00</published><updated>2009-04-14T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-04-14:/posts/2009/04/14/emacs_latex_and_pdf_viewer.html</id><summary type="html">&lt;p class="first last"&gt;A short note on how-to set a pdf-viewer for LaTeX-generated documents in Emacs.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;My favourite editor Emacs provides a great support for LaTeX document
preparation system. There are several modes that extend the default
latex-mode. My favourite ones are: AUCTex (with Preview-latex) and CDLaTeX.&lt;/p&gt;
&lt;p&gt;By-default LaTeX outputs DVI files and uses xdvi viewer with &amp;quot;View&amp;quot; command.
However it's possible to configure LaTeX to outpud pdf files. In Emacs,
you have to execute (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;M-x&lt;/span&gt; &lt;span class="pre"&gt;tex-pdf-mode&lt;/span&gt;&lt;/tt&gt;) command to set the LaTeX's output
to pdf. If you'd like to have a pdf output for all LaTeX documents, add&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TeX-PDF-mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;to your &lt;tt class="docutils literal"&gt;.emacs&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Now, let's add a pdf-viwer to be executed on &amp;quot;View&amp;quot; command (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C-c&lt;/span&gt; &lt;span class="pre"&gt;C-v&lt;/span&gt;&lt;/tt&gt;).
I use GNOME's default Evince document viewer for pdf files. So, the code that
should be added to .emacs is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pdfevince&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;TeX-output-view-style&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="o"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;^pdf$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;evince %o %(outpage)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;LaTeX-mode-hook&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;pdfevince&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; AUCTeX LaTeX mode&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;That's it!&lt;/p&gt;
</content><category term="Articles"/><category term="Elisp"/><category term="Emacs"/><category term="LaTeX"/></entry><entry><title>Byte-compiled ChangeLog</title><link href="https://zaurnasibov.com/posts/2009/04/03/byte_compiled_changelog.html" rel="alternate"/><published>2009-04-03T12:00:00+03:00</published><updated>2009-04-03T12:00:00+03:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-04-03:/posts/2009/04/03/byte_compiled_changelog.html</id><summary type="html">&lt;p class="first last"&gt;My favourite all-purpose, extensible and customizable editor is Emacs. Mastering Emacs takes months, even years, and there is always a lot to discover. For example, I've just seen how Emacs tried to byte-compile a simple ChangeLog text document. How could that happen?&lt;/p&gt;
</summary><content type="html">&lt;p&gt;My dot emacs file is divided into .el pieces like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~/.emacs/conf/env_internal.el&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~/.emacs/conf/env_external.el&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~/.emacs/conf/ui.el&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;; ...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;It's much easier to deal with functions grouped in different files rather
than functions in one big &lt;tt class="docutils literal"&gt;.emacs.el&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The following &amp;quot;trick&amp;quot; automatically byte-compiles .el files as they're
being saved in Emacs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;autocompile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;bytecomp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;numberp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;byte-compile-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;after-save-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;autocompile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;It worked perfect for me, until once I was updating a single ChangeLog file
via Emacs. When I saved it, Emacs tried to byte-compile the file! That was
weird.&lt;/p&gt;
&lt;p&gt;The error should have not been in Emacs (that's true for 99.9%
Emacs-related &amp;quot;bugs&amp;quot;), but somewhere in one of my configuration .el files.
And probably there was something wrong with the byte-compile-on-save hook.
The only function that could cause it was:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;numberp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;Let's see what Emacs says about the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;string-match()&lt;/span&gt;&lt;/tt&gt; function:&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(string-match&lt;/span&gt; regexp string &amp;amp; optional start)&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;Returns the index of start of the first match for regexp in string,
or &lt;tt class="docutils literal"&gt;nil&lt;/tt&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;string-match()&lt;/span&gt;&lt;/tt&gt; works with regexps! And I have the &amp;quot;.&amp;quot; symbol in
the pattern. But period stands for a special character in regexps:&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;'.' (Period)&lt;/tt&gt;
is a special character that matches any single character except a
newline. Using concatenation, we can make regular expressions
like &lt;tt class="docutils literal"&gt;'a.b'&lt;/tt&gt;, which matches any three-character string that begins
with &lt;tt class="docutils literal"&gt;'a'&lt;/tt&gt; and ends with &lt;tt class="docutils literal"&gt;'b'&lt;/tt&gt;.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Emacs help&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;(string-match&lt;/span&gt; &amp;quot;.el&amp;quot; &lt;span class="pre"&gt;buffer-file-name)&lt;/span&gt;&lt;/tt&gt; function call is wrong! For
example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ChangeLog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;returns 4.&lt;/p&gt;
&lt;p&gt;I had to use a backslash to quote that period, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ChangeLog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;But somehow, that didn't work either. An additional documentation exploration
had shown that&lt;/p&gt;
&lt;blockquote class="epigraph"&gt;
&lt;p&gt;When you use regular expressions in a Lisp program, each &lt;tt class="docutils literal"&gt;'\'&lt;/tt&gt; must be
doubled.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;Emacs help&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally, I tried:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ChangeLog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;And it worked! The result was &lt;cite&gt;nil&lt;/cite&gt;. And the result for any file with .el
extension was the start position of the &amp;quot;.el&amp;quot; string in file's name.&lt;/p&gt;
&lt;p&gt;Here is the final version for automatic byte-compile when saving a file with
.el extension:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;
&lt;span class="normal"&gt;3&lt;/span&gt;
&lt;span class="normal"&gt;4&lt;/span&gt;
&lt;span class="normal"&gt;5&lt;/span&gt;
&lt;span class="normal"&gt;6&lt;/span&gt;
&lt;span class="normal"&gt;7&lt;/span&gt;
&lt;span class="normal"&gt;8&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;autocompile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;compile itself if contains .el&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interactive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;bytecomp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;numberp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;string-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\.el&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;byte-compile-file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;buffer-file-name&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;after-save-hook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;#39;autocompile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;That was a funny problem and it took me about half an hour to deal with.
Emacs help helps :)&lt;/p&gt;
</content><category term="Articles"/><category term="programming"/><category term="Emacs"/><category term="Elisp"/><category term="regex"/></entry><entry><title>Beginner's guide to creating a GNOME 2 applet with Python (Part I)</title><link href="https://zaurnasibov.com/posts/2009/02/25/gnome_applet_with_python_part_1.html" rel="alternate"/><published>2009-02-25T12:00:00+02:00</published><updated>2009-02-25T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-02-25:/posts/2009/02/25/gnome_applet_with_python_part_1.html</id><summary type="html">&lt;p class="first last"&gt;A bootstrap guide on creating Gnome2 panel applets with Python.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Programming is an art.
To be more specific, it's an everlasting art. There is no program that
could completely satisfy a user. And I doubt that there is a program
that could completely satisfy a programmer.&lt;/p&gt;
&lt;p&gt;I spend hours in front of my computer. Of course that is very unhealthy
for the eyes. I wanted to create a simple reminder applet - an eyes icon
that changes to &amp;quot;bloody&amp;quot; eyes - indicating that it's time to relax.&lt;/p&gt;
&lt;p&gt;This was my first GNOME applet, my first GTK and more or less serious
Python experience and I'd like too share it with everyone, who deals with
his or her first GNOME applet.&lt;/p&gt;
&lt;p&gt;I hope, this tutorial will help you.&lt;/p&gt;
&lt;div class="section" id="part-i-gnome-applet-basics"&gt;
&lt;h2&gt;Part I: GNOME applet basics&lt;/h2&gt;
&lt;p&gt;Before we begin...
Some technical information about my working environment. I used Ubuntu 9.04
and Python 2.6. So, when I'm saying that &amp;quot;this library loads files from
here&amp;quot;, I'm speaking of what I've found in my working environment. It could
be different in yours.&lt;/p&gt;
&lt;div class="section" id="project-s-directory"&gt;
&lt;h3&gt;1. Project's directory&lt;/h3&gt;
&lt;p&gt;First, lets create a directory for the applet.
&lt;tt class="docutils literal"&gt;/home/user/applet/ &lt;span class="pre"&gt;(~/applet/)&lt;/span&gt;&lt;/tt&gt; will do, of course you can create it as
a symbolic link to your designated path. Here, &lt;tt class="docutils literal"&gt;/home/user/&lt;/tt&gt; is a path
to your home directory. The source code of the applet will be located in
&lt;tt class="docutils literal"&gt;/home/user/applet/src/ &lt;span class="pre"&gt;(~/applet/src/)&lt;/span&gt;&lt;/tt&gt; directory.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-gnome-interacts-with-applets"&gt;
&lt;h3&gt;2. How GNOME interacts with applets&lt;/h3&gt;
&lt;p&gt;In GNOME, an applet is a small application, designed to sit in the GNOME
panel, providing quick and easy access to a control, such as a volume
control, a clock, a network status display, or even a weather gauge &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Technically, applets are Bonobo controls &lt;a class="footnote-reference" href="#footnote-2" id="footnote-reference-2"&gt;[2]&lt;/a&gt; embedded in the Gnome panel.
This means that there are few slight differences from stand-alone GNOME
programs. The first difference is that each applet requires a 'server'
file, which contains a description of the Bonobo capabilities &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-3"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;GNOME searches for applet server files in &lt;tt class="docutils literal"&gt;/usr/lib/bonobo/servers&lt;/tt&gt;
directory.&lt;/p&gt;
&lt;p&gt;The basic part of a simple server file contains server's id and location
of an executable file (our file is a python script):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_info&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;iid=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OAFIID:SampleApplet_Factory&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;exe&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="na"&gt;location=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/home/user/applet/src/applet.py&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;repo_ids&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stringv&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDL:Bonobo/GenericFactory:1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDL:Bonobo/Unknown:1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/oaf_attribute&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sample Applet Factory&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sample Applet&amp;#39;s factory that launches the applet&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/oaf_server&amp;gt;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;iid=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OAFIID:SampleApplet&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;factory&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="na"&gt;location=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;OAFIID:SampleApplet_Factory&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;repo_ids&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stringv&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDL:GNOME/Vertigo/PanelAppletShell:1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDL:Bonobo/Control:1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IDL:Bonobo/Unknown:1.0&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/oaf_attribute&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Sample Applet&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;panel:category:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Utility&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;panel:icon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;no-picture-yet.png&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/oaf_server&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/oaf_info&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;For simplicity, the 'factory' is called &lt;strong&gt;SampleApplet_Factory&lt;/strong&gt; and
&lt;tt class="docutils literal"&gt;home/user/applet/src/applet.py&lt;/tt&gt; is the absolute path to the executable
Python script.&lt;/p&gt;
&lt;p&gt;So, the fist step is to create a server file in &lt;tt class="docutils literal"&gt;/usr/lib/bonobo/servers&lt;/tt&gt;.
Let's name it SampleApplet.server.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;The root privileges are required to work with the SampleApplet.server
file. Remember to correct the /home/user/ path&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;After that, the GNOME session could be restarted (restarting X-server via
Ctrl+Alt+Backspace will do). Try adding the new applet to a panel. The dialog
should look like this:&lt;/p&gt;
&lt;img alt="Add to Panel dialog" class="align-center" src="https://zaurnasibov.com/articles/2009_02_25_gnome_applet_with_python_part_1/gnomeapplet_1_select_applet_1.png" /&gt;
&lt;p&gt;The applet's image is absent, because it doesn't exist in
&lt;strong&gt;/usr/share/pixmaps&lt;/strong&gt;. The applet engine searches for an image according to
our .server file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;oaf_attribute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;panel:icon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;string&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;no-picture-yet.png&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;value=&amp;quot;no-picture-yet.png&amp;quot;&lt;/strong&gt; string should be changed to
&lt;strong&gt;value=&amp;quot;gnome-laptop.png&amp;quot;&lt;/strong&gt;. After restarting GNOME session the
&amp;quot;Add to panel&amp;quot; dialog should look like this:&lt;/p&gt;
&lt;img alt="Add to Panel dialog" class="align-center" src="https://zaurnasibov.com/articles/2009_02_25_gnome_applet_with_python_part_1/gnomeapplet_1_select_applet_2.png" /&gt;
&lt;p&gt;If by accident the gnome-laptop.png is absent, it could be saved to
&lt;strong&gt;/usr/share/pixmaps&lt;/strong&gt; from here:&lt;/p&gt;
&lt;img alt="laptop" class="align-center" src="https://zaurnasibov.com/articles/2009_02_25_gnome_applet_with_python_part_1/gnomeapplet_1_gnome-laptop.png" /&gt;
&lt;p&gt;It's time to write a few lines of code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="launching-the-applet"&gt;
&lt;h3&gt;3.1 Launching the applet&lt;/h3&gt;
&lt;p&gt;Let's start with creating an &lt;strong&gt;applet.py&lt;/strong&gt; script file in &lt;strong&gt;~/applet/src&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The next step, is to define the interpreter that'll handle the script
(this is where programming starts):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="ch"&gt;#!/usr/bin/env python&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;/usr/bin&lt;/strong&gt; is a standard directory on Unix-like operating systems
that contains most of the executable files (i.e., ready-to-run programs)
that are not needed for booting (i.e., starting) or repairing the system &lt;a class="footnote-reference" href="#footnote-3" id="footnote-reference-4"&gt;[3]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some modules should be imported: The pyGTK module is needed to specify the
GTK version used (2.x in this article), the gnome module, that contains all
the useful classes and methods about the GNOME desktop environment, i.e. the
applet class, and the gtk module, Python bindings for the GTK toolkit &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-5"&gt;[4]&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;gtk&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pygtk&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;gnomeapplet&lt;/span&gt;

&lt;span class="n"&gt;pygtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;2.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;iid&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;It works!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Factory started&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;# testing for execution&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Starting factory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bonobo_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OAFIID:SampleApplet_Factory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                               &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__gtype__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                               &lt;span class="s1"&gt;&amp;#39;Sample Applet&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                               &lt;span class="n"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;The applet_factory function receives the object to be initialized (the
applet) and the bonobo activation ID that the new factory will implement.
It returns True if no errors were reported. Then the bonobo_factory
function is called &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-6"&gt;[4]&lt;/a&gt;.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p class="last"&gt;Remember to change the mode of the applet.py file to +x (execute/search),
e.g. by running &lt;strong&gt;chmod 755 ~/applet/src/applet.py&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;The bonobo_factory(IID,Type,Description,Version,Callback) arguments are:
* &lt;em&gt;IID&lt;/em&gt;: The bonobo-activation id of the factory.
* &lt;em&gt;Type&lt;/em&gt;: the type of the created object.
* &lt;em&gt;Description&lt;/em&gt;
* &lt;em&gt;Version&lt;/em&gt;
* &lt;em&gt;Factory callback&lt;/em&gt;: the name of the factory function&lt;/p&gt;
&lt;p&gt;&amp;quot;It works!&amp;quot; label should appear on a panel:&lt;/p&gt;
&lt;img alt="Applet window" class="align-center" src="https://zaurnasibov.com/articles/2009_02_25_gnome_applet_with_python_part_1/gnomeapplet_1_applet_sample.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="debugging-routine"&gt;
&lt;h3&gt;3.2 Debugging routine&lt;/h3&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;print()&lt;/tt&gt; function calls should print the text to the output stream.
But where is the output? A common issue when developing an applet is the
debug process which means, knowing what it's failing and why. As an applet
is nothing but a GTK+ application we can use an additional command line
argument like &amp;quot;run-in-window&amp;quot; to put it in window-mode by creating a GTK+
window and inserting the applet in it &lt;a class="footnote-reference" href="#footnote-4" id="footnote-reference-7"&gt;[4]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It could be done making some changes in the code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="c1"&gt;# testing for execution&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Starting factory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&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;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-d&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# debugging&lt;/span&gt;
        &lt;span class="n"&gt;mainWindow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Window&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;mainWindow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Applet window&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mainWindow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;destroy&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main_quit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;applet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Applet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reparent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mainWindow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mainWindow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;gtk&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bonobo_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;OAFIID:SampleApplet_Factory&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;gnomeapplet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Applet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__gtype__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="s1"&gt;&amp;#39;Sample applet&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0.1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                   &lt;span class="n"&gt;applet_factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;A GTK window is created, its title is set and the &lt;tt class="docutils literal"&gt;'destroy'&lt;/tt&gt; signal is
connected to the &lt;tt class="docutils literal"&gt;gkt.main_quit&lt;/tt&gt; callback. It means that
&lt;tt class="docutils literal"&gt;gtk.main_quit()&lt;/tt&gt; will be automatically called, when the window is
destroyed (closed). We create GNOME applet's instance and make it a child
control (widget) of the window we've just created.
The &lt;tt class="docutils literal"&gt;gtk.main()&lt;/tt&gt; function runs the main loop until the &lt;tt class="docutils literal"&gt;gtk.main_quit()&lt;/tt&gt;
function is called &lt;a class="footnote-reference" href="#footnote-5" id="footnote-reference-8"&gt;[5]&lt;/a&gt;. The GTK+ main loop's primary role is to listen
for events on a file descriptor connected to the X server, and forward
them to widgets &lt;a class="footnote-reference" href="#footnote-6" id="footnote-reference-9"&gt;[6]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now the applet can be launched from a console with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-d&lt;/span&gt;&lt;/tt&gt; key, e.g.
&lt;tt class="docutils literal"&gt;./applet.py &lt;span class="pre"&gt;-d&lt;/span&gt;&lt;/tt&gt;. The applet should appear in a window. It's a common
GNOME window:&lt;/p&gt;
&lt;img alt="Applet window" class="align-center" src="https://zaurnasibov.com/articles/2009_02_25_gnome_applet_with_python_part_1/gnomeapplet_1_applet_debug.png" /&gt;
&lt;/div&gt;
&lt;div class="section" id="references"&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[1]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#footnote-reference-1"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#footnote-reference-3"&gt;2&lt;/a&gt;)&lt;/em&gt; &lt;a class="reference external" href="http://projects.gnome.org/ORBit2/appletstutorial.html"&gt;http://projects.gnome.org/ORBit2/appletstutorial.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-2" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-2"&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Bonobo_(component_model"&gt;http://en.wikipedia.org/wiki/Bonobo_(component_model&lt;/a&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-3" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-4"&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.linfo.org/usr_bin.html"&gt;http://www.linfo.org/usr_bin.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-4" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;[4]&lt;/td&gt;&lt;td&gt;&lt;em&gt;(&lt;a class="fn-backref" href="#footnote-reference-5"&gt;1&lt;/a&gt;, &lt;a class="fn-backref" href="#footnote-reference-6"&gt;2&lt;/a&gt;, &lt;a class="fn-backref" href="#footnote-reference-7"&gt;3&lt;/a&gt;)&lt;/em&gt; &lt;a class="reference external" href="http://www.pygtk.org/articles/applets_arturogf"&gt;http://www.pygtk.org/articles/applets_arturogf&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-5" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-8"&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://www.pygtk.org/docs/pygtk/gtk-functions.html"&gt;http://www.pygtk.org/docs/pygtk/gtk-functions.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-6" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-9"&gt;[6]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://developer.gnome.org/doc/GGAD/sec-mainloop.html"&gt;http://developer.gnome.org/doc/GGAD/sec-mainloop.html&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Articles"/><category term="Gnome"/><category term="programming"/><category term="Python"/></entry><entry><title>The legacy of the initramfs optimization</title><link href="https://zaurnasibov.com/posts/2009/01/11/the_legacy_of_the_initramfs_optimization.html" rel="alternate"/><published>2009-01-11T12:00:00+02:00</published><updated>2009-01-11T12:00:00+02:00</updated><author><name>Zaur Nasibov</name></author><id>tag:zaurnasibov.com,2009-01-11:/posts/2009/01/11/the_legacy_of_the_initramfs_optimization.html</id><summary type="html">&lt;p class="first last"&gt;An adventure of dealing with &lt;tt class="docutils literal"&gt;Target filesystem doesn't have /sbin/init&lt;/tt&gt;&lt;/p&gt;
</summary><content type="html">&lt;p&gt;I was shocked receiving the &lt;tt class="docutils literal"&gt;Target filesystem doesn't have /sbin/init&lt;/tt&gt;
message. I've surfed the Internet for possible solutions - none of them
helped. I had to remember everything I've changed in my system during
past 3 months. Finally, I remembered..&lt;/p&gt;
&lt;p&gt;I'm a Linux person. I'm a Linux person since March 2008. My current OS is
Ubuntu Linux (x86). But I don't like to be &amp;quot;generic&amp;quot;. My x64 processor is not
generic, it's Core2. I have one particular Ethernet, wi-fi and bluetooth
adapter, one sound and video card. I'll never use the 95% of Linux-supported
hardware..&lt;/p&gt;
&lt;p&gt;So, I've compiled my custom &amp;quot;sony-vaio&amp;quot; kernel, still always downloaded the
generic kernel upgrades (to have a native kernel full of modules in a case
of emergency).&lt;/p&gt;
&lt;p&gt;This happened when I've updated the system.&lt;/p&gt;
&lt;p&gt;Ubuntu has downloaded the linux-image-2.6.11-generic kernel. I wanted to
check, If my motioneye camera works under it, so, I rebooted the computer
and selected the &lt;strong&gt;Ubuntu 8.10, kernel 2.6.27-11-generic&lt;/strong&gt; option. Bump!&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;Target filesystem doesn't have /sbin/init&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;I had no ideas of what did that mean. I rebooted the laptop via
&lt;strong&gt;Ctrl+Alt+PrintScreen+B&lt;/strong&gt;. Fortunately my custom kernel was working fine.
After an hour of surfing the Internet I already knew, that possibly the
kernel can't mount a root file system. So, the difference was between my
custom kernel and the generic kernel. I was annoyed. There was nothing in my
kernel, that  generic kernel didn't have. But wait! While creating my custom
kernel, I've compiled the ext3 filesystem support &lt;strong&gt;statically&lt;/strong&gt; into it.
But why the generic kernel can't load the ext3 module?&lt;/p&gt;
&lt;p&gt;Suddenly it dawned upon me.&lt;/p&gt;
&lt;p&gt;There is initial ram disk stuff at the beginning of system load process.&lt;/p&gt;
&lt;blockquote&gt;
The initial ramdisk, or initrd is a temporary file system commonly used
by the Linux kernel during boot. The initrd is typically used for making
preparations before the real root file system can be mounted &lt;a class="footnote-reference" href="#footnote-1" id="footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;So, possibly the initrd image created for the generic kernel didn't contain
the ext3 module. How could that happen? It could, if you're a person who
likes to optimize everything that could be optimized. For example, the
system's boot-time.&lt;/p&gt;
&lt;p&gt;There is a minimal set of modules enough to load a system both from hibernate
(suspend2disk) and powered-off conditions. By default, the initrd contains
&amp;quot;most&amp;quot; modules (see /etc/initramfs-tools/initramfs.conf file). In my case the
MODULES option was changed like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt;1&lt;/span&gt;
&lt;span class="normal"&gt;2&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;#MODULES=most
MODULES=list
&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;
&lt;p&gt;I used next steps to generate the modules list:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Boot kernel with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;init=/bin/sh&lt;/span&gt;&lt;/tt&gt; option&lt;/li&gt;
&lt;li&gt;Execute &lt;tt class="docutils literal"&gt;sudo lsmod | tail &lt;span class="pre"&gt;-n&lt;/span&gt; +2 | sort | awk '{print &lt;span class="pre"&gt;$1;}'&lt;/span&gt; &amp;gt;
&lt;span class="pre"&gt;/etc/initramfs-tools/modules&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Execute &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;update-initramfs&lt;/span&gt; &lt;span class="pre"&gt;-v&lt;/span&gt; &lt;span class="pre"&gt;-d&lt;/span&gt; &lt;span class="pre"&gt;-k&lt;/span&gt;
\`uname &lt;span class="pre"&gt;-r`&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="pre"&gt;update-initramfs&lt;/span&gt; &lt;span class="pre"&gt;-v&lt;/span&gt; &lt;span class="pre"&gt;-c&lt;/span&gt; &lt;span class="pre"&gt;-k&lt;/span&gt; \`uname &lt;span class="pre"&gt;-r`&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The second line copies all loaded modules' names to
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/initramfs-tools/modules&lt;/span&gt;&lt;/tt&gt; file. The third line updates the current
kernel's initramfs file.&lt;/p&gt;
&lt;p&gt;As you might already found out, there was no ext3 module in the list, because
my custom kernel didn't need an ext3 module!&lt;/p&gt;
&lt;p&gt;But Ubuntu's generic kernel has the ext3 as a module!
So, to boot a system with generic kernel, I should have had an &amp;quot;ext3&amp;quot; line
in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/initramfs-tools/modules&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;It didn't take long. I updated the file and called
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;update-initramfs&lt;/span&gt; &lt;span class="pre"&gt;-c&lt;/span&gt; &lt;span class="pre"&gt;-k&lt;/span&gt; all&lt;/tt&gt;
to regenerate the init ram disks for both kernels (actually I didn't need
to do that for my custom kernel :).&lt;/p&gt;
&lt;p&gt;At last, I could load the system with new 2.6.27.11 kernel.&lt;/p&gt;
&lt;table class="docutils footnote" frame="void" id="footnote-1" rules="none"&gt;
&lt;colgroup&gt;&lt;col class="label" /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="label"&gt;&lt;a class="fn-backref" href="#footnote-reference-1"&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Initrd"&gt;http://en.wikipedia.org/wiki/Initrd&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content><category term="Articles"/><category term="initramfs"/><category term="Linux"/></entry></feed>