<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Ronan's Tech Blog</title><link href="http://blog.rklyne.net/" rel="alternate"></link><link href="blog.rklyne.net/feeds/all.atom.xml" rel="self"></link><id>http://blog.rklyne.net/</id><updated>2019-03-01T15:26:00+00:00</updated><entry><title>Quick useful python profiling</title><link href="http://blog.rklyne.net/quick-useful-python-profiling.html" rel="alternate"></link><published>2019-03-01T15:26:00+00:00</published><updated>2019-03-01T15:26:00+00:00</updated><author><name>Ronan Klyne</name></author><id>tag:blog.rklyne.net,2019-03-01:/quick-useful-python-profiling.html</id><summary type="html">&lt;h1&gt;Profiling your process&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python -m cProfile -o profile_data.pstats my_program.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run python like this and it will create a file full of profiling stats.&lt;/p&gt;
&lt;h1&gt;Viewing the data&lt;/h1&gt;
&lt;p&gt;&lt;a href="http://jiffyclub.github.io/snakeviz/"&gt;SnakeViz&lt;/a&gt; rocks. It's a lovely little visualisation tool that makes it very easy to see where your time is going&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pip install …&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;h1&gt;Profiling your process&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;python -m cProfile -o profile_data.pstats my_program.py
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Run python like this and it will create a file full of profiling stats.&lt;/p&gt;
&lt;h1&gt;Viewing the data&lt;/h1&gt;
&lt;p&gt;&lt;a href="http://jiffyclub.github.io/snakeviz/"&gt;SnakeViz&lt;/a&gt; rocks. It's a lovely little visualisation tool that makes it very easy to see where your time is going&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;pip install snakeviz
snakeviz profile_data.pstats
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This will launch a web server and your browser to interactively inspect the results. Enjoy!&lt;/p&gt;
&lt;p&gt;&lt;img alt="SnakeViz sunburst view screenshot" src="http://blog.rklyne.net/images/python-snakeviz-sunburst.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="SnakeViz icicle view screenshot" src="http://blog.rklyne.net/images/python-snakeviz.png"&gt;&lt;/p&gt;</content><category term="python"></category><category term="profiling"></category><category term="quick"></category></entry><entry><title>Testing interface contracts in Python</title><link href="http://blog.rklyne.net/testing-interface-contracts-in-python.html" rel="alternate"></link><published>2019-02-24T09:02:00+00:00</published><updated>2019-02-24T09:02:00+00:00</updated><author><name>Ronan Klyne</name></author><id>tag:blog.rklyne.net,2019-02-24:/testing-interface-contracts-in-python.html</id><summary type="html">&lt;p&gt;I've been writing some interface heavy code in Python recently and have developed a pattern that I really like and have not seen before.
I think this is original but I doubt it's the first. I'd like to hear about any similar approaches that have been documented.&lt;/p&gt;
&lt;h2&gt;Interfaces in Python …&lt;/h2&gt;</summary><content type="html">&lt;p&gt;I've been writing some interface heavy code in Python recently and have developed a pattern that I really like and have not seen before.
I think this is original but I doubt it's the first. I'd like to hear about any similar approaches that have been documented.&lt;/p&gt;
&lt;h2&gt;Interfaces in Python&lt;/h2&gt;
&lt;p&gt;They aren't used as widely as they could be, owing to the dynamic nature of Python and it's tendency towards duck typing.&lt;/p&gt;
&lt;p&gt;Still, there's some very good support for them in community tooling. I make very good use of pylint for detecting interface completion.&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# src/interface/knight.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Knight&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="nf"&gt;say_ni&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;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_able&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;is_able&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;NotImplementedError&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;drink&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;raise&lt;/span&gt; &lt;span class="ne"&gt;NotImplementedError&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NotAbleToDrinkError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;Exception&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;p&gt;&lt;code&gt;pylint&lt;/code&gt; will detect that this is an abstract method and if your subclasses fail to implement it then it says so. This is nice but isn't nearly enough to guarantee correct behaviour.&lt;/p&gt;
&lt;h2&gt;Interface contracts&lt;/h2&gt;
&lt;p&gt;The contract is our specification for how an interface must behave.
In the case of our &lt;code&gt;Knight&lt;/code&gt;, the knights must be able to say "ni" and they must drink whenever they are able.&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# src/implementation1/test_knight.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;implementation_module&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Knight&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestKnightContract&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_can_say_ni_without_issues&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Knight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;say_ni&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_drinks_when_able&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Knight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_able&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_does_not_drink_when_unable&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Knight&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_able&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;with&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;assertRaises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotAbleToDrinkError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drink&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;p&gt;That's a simple test for a knight's interface contract. All good so far but it falls down when we have multiple implementations of our interface. We end up writing the same contract out again and again.&lt;/p&gt;
&lt;h2&gt;DRY - one contract better than repeated tests&lt;/h2&gt;
&lt;p&gt;Normally if someone recommends deduplicating test code "because it's more DRY" I feel compelled to remind them that DRY is about ideas, not about lines of code.
In this case we are dealing with the same idea so we should re-use the same code. There is only one contract that all must obey.&lt;/p&gt;
&lt;p&gt;My emerging pattern for implementation of this looks a little unusual - it's defining a class inside a method in order to bind the &lt;code&gt;knight_factory&lt;/code&gt; into the closure.&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# src/interfaces/knight_contract.py&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.knight&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NotAbleToDrinkError&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;contract_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knight_factory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestKnightContract&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_can_say_ni_without_issues&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;knight_factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;say_ni&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_drinks_when_able&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;knight_factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_able&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_does_not_drink_when_unable&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;knight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;knight_factory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_able&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;with&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;assertRaises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NotAbleToDrinkError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;knight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drink&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;TestKnightContract&lt;/span&gt;


&lt;span class="c1"&gt;# src/implementation1/test_knight.py&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;..interface.knight_contract&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;contract_test&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.knight&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Knight&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestKnight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contract_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Knight&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;p&gt;This pattern can now be used to implement the same contract in multiple places. When the contract needs clarifying with another test you can be sure that all implementations follow it.&lt;/p&gt;
&lt;p&gt;Note that we subclass to create this test instead of simply &lt;code&gt;TestKnight = contract_test(Knight)&lt;/code&gt;.
That simple assignment would run the tests but it would not report which implementation was failing when something broke.&lt;/p&gt;
&lt;h2&gt;A slight modification for Django&lt;/h2&gt;
&lt;p&gt;When writing these contracts for interfaces that can be backed by Django models I found a need to use Django's own &lt;code&gt;TestCase&lt;/code&gt; implementation in order to have the test database set up correctly.&lt;/p&gt;
&lt;p&gt;It's a small tweak:&lt;/p&gt;
&lt;table class="highlighttable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# src/interface/knight_contract.py&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;contract_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knight_generator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KnightContractTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_class&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# On with the tests.&lt;/span&gt;


&lt;span class="c1"&gt;# django/tests/test_knight.py&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DjangoKnightTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contract_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Knight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&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;h2&gt;Problems?&lt;/h2&gt;
&lt;p&gt;As I said as the top, I haven't seen this done before. If there's an issue with this approach that I can't see then I'd love to hear about it.&lt;/p&gt;</content><category term="testing"></category><category term="python"></category><category term="solid"></category></entry><entry><title>Attrs library for Python</title><link href="http://blog.rklyne.net/attrs-library-for-python.html" rel="alternate"></link><published>2019-02-16T11:43:00+00:00</published><updated>2019-02-16T11:43:00+00:00</updated><author><name>Ronan Klyne</name></author><id>tag:blog.rklyne.net,2019-02-16:/attrs-library-for-python.html</id><summary type="html">&lt;p&gt;A quick advertisement.&lt;/p&gt;
&lt;p&gt;I love &lt;a href="https://hynek.me"&gt;Hynek Schlawack&lt;/a&gt;'s &lt;a href="https://attrs.readthedocs.io/en/stable/"&gt;attrs library&lt;/a&gt;. It's had a subtle but greatly clarifying influence on my code since I discovered it.&lt;/p&gt;
&lt;p&gt;If you're not familiar with that library then I highly recommend reading about it. &lt;/p&gt;
&lt;p&gt;It means you can write simple objects like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;@attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;
&lt;span class="kr"&gt;class …&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;A quick advertisement.&lt;/p&gt;
&lt;p&gt;I love &lt;a href="https://hynek.me"&gt;Hynek Schlawack&lt;/a&gt;'s &lt;a href="https://attrs.readthedocs.io/en/stable/"&gt;attrs library&lt;/a&gt;. It's had a subtle but greatly clarifying influence on my code since I discovered it.&lt;/p&gt;
&lt;p&gt;If you're not familiar with that library then I highly recommend reading about it. &lt;/p&gt;
&lt;p&gt;It means you can write simple objects like&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kd"&gt;@attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;
&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ib&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Which are equivalent to&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="kr"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Thing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;__str__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;usual&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt;

    &lt;span class="nx"&gt;def&lt;/span&gt; &lt;span class="nx"&gt;__eq__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;usual&lt;/span&gt; &lt;span class="nx"&gt;thing&lt;/span&gt;

    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="nx"&gt;All&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;other&lt;/span&gt; &lt;span class="nx"&gt;dunder&lt;/span&gt; &lt;span class="nx"&gt;methods&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The docs have &lt;a href="https://attrs.readthedocs.io/en/stable/examples.html"&gt;much better examples than I could repeat here&lt;/a&gt;. You should check it out.&lt;/p&gt;</content><category term="python"></category><category term="libraries"></category></entry><entry><title>Django ports &amp; adapters series, laying out the problem</title><link href="http://blog.rklyne.net/django-ports-adapters-series-laying-out-the-problem.html" rel="alternate"></link><published>2019-02-16T07:27:00+00:00</published><updated>2019-02-16T07:27:00+00:00</updated><author><name>Ronan Klyne</name></author><id>tag:blog.rklyne.net,2019-02-16:/django-ports-adapters-series-laying-out-the-problem.html</id><summary type="html">&lt;h2&gt;Start from the beginning...&lt;/h2&gt;
&lt;p&gt;This is my introduction piece to this blog series and lays out how I came to be tackling this problem.&lt;/p&gt;
&lt;p&gt;Django is a great system for getting started with a web project but it starts to strain as the project grows. Their ethos is to make …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Start from the beginning...&lt;/h2&gt;
&lt;p&gt;This is my introduction piece to this blog series and lays out how I came to be tackling this problem.&lt;/p&gt;
&lt;p&gt;Django is a great system for getting started with a web project but it starts to strain as the project grows. Their ethos is to make the simple things easy and the complex things possible. I'm using Django heavily at the moment and I'm feeling some of these strains. This series is about addressing those issues in a maintainable way using the &lt;a href="http://wiki.c2.com/?PortsAndAdaptersArchitecture"&gt;Ports and Adapters&lt;/a&gt; architecture.&lt;/p&gt;
&lt;p&gt;It's an opinionated framework in the sense that it makes some choices for you. This is a necessary part of making simple things easy.
One of the choices that is made for you is to use the &lt;a href="https://martinfowler.com/eaaCatalog/activeRecord.html"&gt;Active record pattern&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Escaping Active Record&lt;/h2&gt;
&lt;p&gt;Active record is familiar to most Django programmers, by experience if not by name. The &lt;code&gt;models.Model&lt;/code&gt; base class is Django's implementation of it. Like any software design choice there are strengths and weaknesses. In accordance with Django's ethos, this choice is aimed at making the simple things easy.&lt;/p&gt;
&lt;p&gt;Active record is the practise of building your domain model, domain logic and database model into one object. This is a shortcut that can be taken when the two objects overlap. It's really good when the database table layout and the in-memory domain model are the same - of course you'd use the same object there. Conversely, if the two models are very different then you don't want them to be the same object.&lt;/p&gt;
&lt;p&gt;Usually a system will start out simple and grow. It will slowly transition from being well suited to ActiveRecord into something that's really not. This has happened to me.&lt;/p&gt;
&lt;p&gt;I've got a professional project where there are dozens of models with hundreds of views. Refactoring the database schema has become hard because there are too many pieces of code dependent on it. Too much complexity is brought in by depending on a detail instead of an abstraction. The views and controllers all depend on the domain model and reference its API. This is good and correct. The problem we have with active record is that the views also depend on the persistence model.&lt;/p&gt;
&lt;p&gt;This is tight coupling from one IO mechanism to another and our domain logic is caught in the middle. This puts us in the position of needing to trade off between performance, maintainability and domain model complexity. The performance is necessary and the domain model is out of our control so maintainability suffers if the system continues being developed without addressing this issue.&lt;/p&gt;
&lt;p&gt;Have you ever heard a colleague calling user requirements "stupid"? Then some part of the business insists that it's built anyway and everyone gets more tense? This is my litmus test. A code smell without code. The forced complexity from the domain model has nowhere to go when the domain logic depends on other complex details like persistence.&lt;/p&gt;
&lt;h2&gt;Ports and adapters&lt;/h2&gt;
&lt;p&gt;Ports and adapters is an architecture pattern very well suited to this situation. It puts domain models and business logic at the core of your program and makes everything else depend on them. These are the details of the real world that don't change nearly as often as database technologies, messaging frameworks, the number of customers your product needs to support or usage patterns of users.&lt;/p&gt;
&lt;p&gt;The pattern says that everything outside of the domain model should depend on the domain model. This allows us to contain complexity in the domain model where it is abundant and keep all other concerns separate. In Django's case that starts with the database but will be extended to signals, background task queues and anything else that occurs along the journey.&lt;/p&gt;
&lt;p&gt;The dependency of our domain logic on the database has to be inverted so that we can freely change either without worrying about breaking the other. The active record stuff is very useful but has to be abstracted.&lt;/p&gt;
&lt;p&gt;It's neatly &lt;a href="http://wiki.c2.com/?PortsAndAdaptersArchitecture"&gt;explained on Ward Cunningham's wiki&lt;/a&gt; and informs &lt;a href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html"&gt;Bob Martin's "clean architecture"&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;So, where to?&lt;/h2&gt;
&lt;p&gt;The next post will show how I started with a domain model built outside Django, built persistence services around it, then brought it in to a Django project whilst retaining the useful properties of the architecture, adding Django models as 'just' another option for persistence.&lt;/p&gt;
&lt;p&gt;I'll go on to explore inserting this architecture into an existing system and refactoring the interfaces involved.&lt;/p&gt;</content><category term="ports+adapters"></category><category term="django"></category><category term="python"></category></entry><entry><title>Welcome</title><link href="http://blog.rklyne.net/first.html" rel="alternate"></link><published>2019-02-12T00:00:00+00:00</published><updated>2019-02-12T00:00:00+00:00</updated><author><name>Ronan Klyne</name></author><id>tag:blog.rklyne.net,2019-02-12:/first.html</id><summary type="html">&lt;p&gt;So ... I'm starting a blog. I made a reckless promise to @hjwp that I'd write up a how-to or two.&lt;/p&gt;
&lt;p&gt;I'll be writing about Python, Django, architecture, patterns, development teams and being understood.&lt;/p&gt;
&lt;p&gt;It'll be interesting to see if that's still true in a few months&lt;/p&gt;</summary><content type="html">&lt;p&gt;So ... I'm starting a blog. I made a reckless promise to @hjwp that I'd write up a how-to or two.&lt;/p&gt;
&lt;p&gt;I'll be writing about Python, Django, architecture, patterns, development teams and being understood.&lt;/p&gt;
&lt;p&gt;It'll be interesting to see if that's still true in a few months&lt;/p&gt;</content><category term="blog"></category></entry></feed>