Jekyll2023-04-08T09:52:25+00:00https://agileabstractions.com/feed.xmlAgile Abstractions: Michael FoordPython Training, Contracting and Consulting. Automated testing specialist.Michael FoordSelenium, jQuery and File uploads2018-11-26T00:00:00+00:002018-11-26T00:00:00+00:00https://agileabstractions.com/selenium<p><img src="/images/selenium.png" alt="Selenium" /></p>
<p>One of the contracts I’ve been working on recently is working with Gurock building a test automation system for a PHP application, their test management app <a href="https://www.gurock.com/testrail">TestRail</a>. As well as building the instrastructure for the application testing and the API testing I’ve once again been involved in the nitty-gritty of testing a web application with <a href="https://www.seleniumhq.org/projects/webdriver/">Selenium</a> and all the fun that involved.</p>
<p>And actually it has been fun. We’ve had a bunch of issues to overcome and despite the usual pain and trauma and running round in circles we seem to have overcome most of them and have a test suite that is robust against the three different platforms we’re testing against.</p>
<p>For those who don’t know Selenium WebDriver interface allows you to connect your Python tests, or just about any language you care to choose, and test you web application as a “black box” - interacting with it in the same way as your users do. These are “functional tests”, as opposed to unit tests”, that tests the whole application as a whole meets its specifications and rquirements. As will all testing you can’t guarantee that it makes your applcation bug-free, but you can eleminiate whole classes of bugs and gurarantee a minimum level of application quality.</p>
<p>This application is written in PHP, but we’re using Python, py.test and Selenium to automate the tests and the front end is built with jQuery. There are various fun aspects of testing this app that we’ve encountered. A couple of these stem from the fact that like any modern any web application much of the UI updates are done from AJAX calls. This means that there’s no global page state ready event to wait for to know that load has finished and the page is ready to interact with.</p>
<p>One of the plugins in use is the <a href="http://malsup.com/jquery/block/">BlockUI plugin</a>. This puts a semi-opaque overlay over the user interface in the browser whilst asynchronous AJAX requests are being made, to prevent other elements of the user interface being interacted with. As the request is an asynchronous one the browser isn’t blocked so our Selenium tests don’t know that the user interface is blocked and it should wait before attempting any more interactions. This causes tests to fail with the dreaded error:</p>
<p><code class="language-plaintext highlighter-rouge">Exception in thread "main" org.openqa.selenium.WebDriverException: unknown error: Element <input type="button" class="btn btn-default" data-toggle="modal" data-target="#adduser" data-localize="adduser" value="Add user"> is not clickable at point (1397, 97). Other element would receive the click: <div class="blockUI blockOverlay" style="z-index: 1000; border: none; margin: 0px; padding: 0px; width: 100%; height: 100%; top: 0px; left: 0px; background-color: rgb(0, 0, 0); cursor: wait; position: absolute; opacity: 0.304712;"></div></code></p>
<p>The dreaded part is specifically <code class="language-plaintext highlighter-rouge">is not clickable at point (1397, 97). Other element would receive the click: <div class="blockUI blockOverlay"</code>.</p>
<p>The “blockUI” element is intercepting the click because the AJAX request is not completed, or more to the point <em>a</em> <code class="language-plaintext highlighter-rouge">blockUI</code> element is intercepting it. The normal way round this would be to find the “blockU” element and wait for it to no longer be displayed. Unfortunately there’s more than one of them! So this is the code we came up with to wait until none of them are displayed:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">selenium.common.exceptions</span> <span class="kn">import</span> <span class="n">StaleElementReferenceException</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.common.by</span> <span class="kn">import</span> <span class="n">By</span>
<span class="k">class</span> <span class="nc">GeneralLocators</span><span class="p">:</span>
<span class="n">blockUI</span> <span class="o">=</span> <span class="p">(</span><span class="n">By</span><span class="p">.</span><span class="n">CLASS_NAME</span><span class="p">,</span> <span class="s">"blockUI"</span><span class="p">)</span>
<span class="n">busy</span> <span class="o">=</span> <span class="p">(</span><span class="n">By</span><span class="p">.</span><span class="n">CLASS_NAME</span><span class="p">,</span> <span class="s">"busy"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">any_elements_displayed</span><span class="p">(</span><span class="n">elements</span><span class="p">):</span>
<span class="k">for</span> <span class="n">element</span> <span class="ow">in</span> <span class="n">elements</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">element</span><span class="p">.</span><span class="n">is_displayed</span><span class="p">():</span>
<span class="k">return</span> <span class="bp">True</span>
<span class="k">except</span> <span class="n">StaleElementReferenceException</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">return</span> <span class="bp">False</span>
<span class="k">class</span> <span class="nc">BasePageElement</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">wait_for_blockui_to_close</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">seconds</span><span class="o">=</span><span class="mi">5</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">implicitly_wait</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">stop</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">+</span> <span class="n">seconds</span>
<span class="k">while</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o"><</span> <span class="n">stop</span><span class="p">:</span>
<span class="n">blockUIs</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">find_elements</span><span class="p">(</span><span class="o">*</span><span class="n">GeneralLocators</span><span class="p">.</span><span class="n">blockUI</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">any_elements_displayed</span><span class="p">(</span><span class="n">blockUIs</span><span class="p">):</span>
<span class="k">return</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
<span class="k">raise</span> <span class="n">TimeoutException</span><span class="p">(</span><span class="s">"Timed out waiting for blockUI to go away"</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">implicitly_wait</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</code></pre></div></div>
<p>We have a similar problem with AJAX elements that don’t block the page, but take several seconds to update, showing a busy indiciator whilst they’re updating. Again, we need to wait for the busy indicators to complete before we ineract with any of the elements. Thanksfully that is similarly easy. Note that we set the global <code class="language-plaintext highlighter-rouge">implicitly_wait</code> timeout to zero whilst we’re checking.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">def</span> <span class="nf">wait_until_not_busy</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">seconds</span><span class="o">=</span><span class="mi">5</span><span class="p">):</span>
<span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">implicitly_wait</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">stop</span> <span class="o">=</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o">+</span> <span class="n">seconds</span>
<span class="k">while</span> <span class="n">time</span><span class="p">.</span><span class="n">time</span><span class="p">()</span> <span class="o"><</span> <span class="n">stop</span><span class="p">:</span>
<span class="n">busy</span> <span class="o">=</span> <span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">find_elements</span><span class="p">(</span><span class="o">*</span><span class="n">GeneralLocators</span><span class="p">.</span><span class="n">busy</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">any_elements_displayed</span><span class="p">(</span><span class="n">busy</span><span class="p">):</span>
<span class="k">return</span>
<span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
<span class="k">raise</span> <span class="n">TimeoutException</span><span class="p">(</span><span class="s">"Timed out waiting to not be busy"</span><span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">implicitly_wait</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
</code></pre></div></div>
<p>It’s well worth noting that with the selenium library in Python, the <code class="language-plaintext highlighter-rouge">implicitly_wait</code> value is a global. Setting it anywhere sets it for the rest of the session.</p>
<p>We put all the element locators into classes, like <code class="language-plaintext highlighter-rouge">GeneralLocators</code> so that as locators change (inevitable in an evolving user interface) there is only one place to change the locators rather than having them scattered through out our code.</p>
<p>Here’s a few more tricks and trips we’ve discovered along the way. Whilst text boxes have a nice and straightforward <code class="language-plaintext highlighter-rouge">.clear()</code> method to clear existing text in them, this dioesn’;t work with a <code class="language-plaintext highlighter-rouge">textarea</code> (which confusingly enough has a <code class="language-plaintext highlighter-rouge">.clear()</code> method which apppears to do nothing. The right way to clear to a text box is to send a CTRL-A followed by a backspace:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1"># CTRL-A plus BACKSPACE are needed for selenium to clear the textarea as .clear() doesn't work.
</span> <span class="bp">self</span><span class="p">.</span><span class="n">send_keys_to_element</span><span class="p">(</span><span class="n">CustomizationsLocators</span><span class="p">.</span><span class="n">add_custom_field_description</span><span class="p">,</span> <span class="n">Keys</span><span class="p">.</span><span class="n">CONTROL</span> <span class="o">+</span> <span class="s">"a"</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">send_keys_to_element</span><span class="p">(</span><span class="n">CustomizationsLocators</span><span class="p">.</span><span class="n">add_custom_field_description</span><span class="p">,</span> <span class="n">Keys</span><span class="p">.</span><span class="n">BACKSPACE</span><span class="p">)</span>
</code></pre></div></div>
<p>If you want to provide a command line option to run the tests with a headless browser, this little function (firefox only) will do the trick. You could further customize is to switch between browers:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pytest</span>
<span class="kn">from</span> <span class="nn">selenium</span> <span class="kn">import</span> <span class="n">webdriver</span>
<span class="kn">from</span> <span class="nn">selenium.webdriver.firefox.options</span> <span class="kn">import</span> <span class="n">Options</span>
<span class="k">def</span> <span class="nf">get_driver</span><span class="p">():</span>
<span class="n">options</span> <span class="o">=</span> <span class="n">Options</span><span class="p">()</span>
<span class="k">if</span> <span class="n">pytest</span><span class="p">.</span><span class="n">config</span><span class="p">.</span><span class="n">getoption</span><span class="p">(</span><span class="s">'headless'</span><span class="p">):</span>
<span class="n">options</span><span class="p">.</span><span class="n">headless</span> <span class="o">=</span> <span class="bp">True</span>
<span class="k">return</span> <span class="n">webdriver</span><span class="p">.</span><span class="n">Firefox</span><span class="p">(</span><span class="n">options</span><span class="o">=</span><span class="n">options</span><span class="p">)</span>
</code></pre></div></div>
<p>And these final two are interesting. Uploading files with Selenium. Because the file upload dialog is a native dialog it’s very hard to interact with Selenium (impossible I thin.). However it does come along with a hidden input field that you can enter file paths directly to. So for a normal file dialog this works fine:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> from selenium.webdriver.common.by import By
file_inputs = driver.find_elements(By.CSS_SELECTOR, 'input.dz-hidden-input')
input_element = file_inputs[input_index]
driver.execute_script('arguments[0].style = ""; arguments[0].style.display = "block"; arguments[0].style.visibility = "visible";', input_element)
time.sleep(0.1)
input_element.send_keys(filename)
</code></pre></div></div>
<p>So long as you know, or work out by trial and error, which file input dialog to send the input to it will work fine. The useful thing is that it exposes all the hidden file inputs in the user interace so you can see what you’re interacting with.</p>
<p>This still unfortunately doesn’t work for file uploads by dropzone, some kind of javascript extension. For this you need to base64 encode the file yourself and attach it to the dropzone. Made all the more interesting by the fact that the <code class="language-plaintext highlighter-rouge">driver.execute_script</code> api will only take a single line of input. Still, it works!! As horrible as it is, this works!! It takes the base64 encoded version of the file and attaches it to the dropzone element as a blob, with the filename attached as metadata.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">def</span> <span class="nf">add_dropzone_attachment</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">locator</span><span class="p">,</span> <span class="n">attachment_path</span><span class="p">):</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">basename</span><span class="p">(</span><span class="n">attachment_path</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">attachment_path</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">content</span><span class="p">).</span><span class="n">decode</span><span class="p">(</span><span class="s">'ascii'</span><span class="p">)</span>
<span class="n">script</span> <span class="o">=</span> <span class="p">(</span>
<span class="s">"var myZone, blob, base64Image; myZone = Dropzone.forElement('{}');"</span>
<span class="s">"base64content = '{}';"</span>
<span class="s">"function base64toBlob(r,e,n)var c=new Blob(a,\{\{type\:e\}\s});return c}}"</span>
<span class="s">"blob = base64toBlob(base64content, 'image/png');"</span>
<span class="s">"blob.name = '{}';"</span>
<span class="s">"myZone.addFile(blob);"</span>
<span class="p">).</span><span class="nb">format</span><span class="p">(</span><span class="n">locator</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="bp">self</span><span class="p">.</span><span class="n">driver</span><span class="p">.</span><span class="n">execute_script</span><span class="p">(</span><span class="n">script</span><span class="p">)</span>
</code></pre></div></div>
<p>The locator is the locator of the dropzone area itself, usually something like <code class="language-plaintext highlighter-rouge">#attachmentDropzone</code>.</p>
<p>Hopefully all this painfully won information proves useful to someone!</p>Michael FoordInterview on Podcast.__init__2018-09-04T00:00:00+00:002018-09-04T00:00:00+00:00https://agileabstractions.com/Podcast<p><img src="/images/podcast-logo.png" alt="Podcast.__init__" /></p>
<p>I recently had the great pleasure of having a conversation with Tobias Macey, who produces the <em>Podcast.<strong>init</strong></em> podcast. We spent almost an hour talking about testing, the Python community and the mock library amongst other things.</p>
<p>The podcast is now available to listen to:</p>
<ul>
<li>
<p><a href="https://youtu.be/c-I0md_3fbQ?t=255">Michael Foord On Testing, Mock, TDD, And The Python Community - Episode 171</a></p>
<p>Michael Foord has been working on building and testing software in Python for over a decade. One of his most notable and widely used contributions to the community is the Mock library, which has been incorporated into the standard library. In this episode he explains how he got involved in the community, why testing has been such a strong focus throughout his career, the uses and hazards of mocked objects, and how he is transitioning to freelancing full time.</p>
</li>
</ul>
<p>A selection of the questions Tobias asked include:</p>
<ul>
<li>How did you get introduced to Python?</li>
<li>One of the main threads in your career appears to be software testing. What aspects of testing do you find so interesting and how did you first get exposed to that aspect of building software?
<ul>
<li>How has the language and ecosystem support for testing evolved over the course of your career?</li>
<li>What are some of the areas that you find it to still be lacking?</li>
</ul>
</li>
<li>Mock is one of your projects that has been widely adopted and ultimately incorporated into the standard library. What was your reason for starting it in the first place?
<ul>
<li>Mocking can be a controversial topic. What are your current thoughts on how and when to use mocks, stubs, and fixtures?</li>
</ul>
</li>
<li>How do you view the state of the art for testing in Python as it compares to other languages that you have worked in?</li>
<li>You were fairly early in the move to supporting Python 2 and 3 in a single project with Mock. How has that overall experience changed in the intervening years since Python 2.4 and 3.2?</li>
<li>What are some of the notable evolutions in Python and the software industry that you have experienced over your career?</li>
<li>You recently transitioned to acting as a software trainer and consultant full time. Where are you focusing your energy currently and what are your grand plans for the future?</li>
</ul>Michael FoordA Very Short Love Letter to Agile2018-07-18T00:00:00+00:002018-07-18T00:00:00+00:00https://agileabstractions.com/Agile<p><img src="/images/resolver.jpg" alt="Resolver Systems 2009" /></p>
<p>The photo shows some of the Resolver Systems crew enjoying a meal together at the 2009 EuroPython in Birmingham.</p>
<p>I love the word rigour. It conveys either, or both, strict discipline or something that was really hard work.</p>
<p>I’ve found the rigorous application of theoretical principles a really useful way of learning those principles. Learning what they really mean, and what those principles are good at achieving and what they’re not good at achieving.</p>
<p>I’ve been rigorous in my discipline in meditating. I’ve meditated for an hour a day, generally six days a week, for a number of years now. A dedicated and regular practise of focus and letting go of distractions, which is the substance of mindfulness practise, has made a difference in my life and my understanding of myself.</p>
<p>My trade is as a software engineer, a computer programmer. I taught myself to program by becoming really passionate about it. What you love you learn. I learned the art and craft of engineering in my first professional job, at a small startup in London called Resolver Systems.</p>
<p>There, for the four years I worked there, we rigorously applied the principles of Extreme Programming, a strict variant and really the progenitor of the “agile” movement. The goal is engineering processes that make the development process agile and fluid, able to change direction quickly and able to check that it is continuously delivering value in the work being done, whilst also creating the software in ways that ensure as much as is possible you are creating a quality and useful product.</p>
<p>This includes full Test Driven Design (often now called “test first” in a great misunderstanding of the value of TDD), with a full test coverage from unit to functional (full stack). We had about three to four times more test code than production code. We built a beautiful thing.</p>
<p>It also included full pair programming. So for four years we worked together and thought together and learned together. The product failed, unfortunately, an idea ahead of its time. With Python finally being added to Excel as a scripting language it’s possible that the idea of applying proper engineering principles to the creation of complex spreadsheets may have its day after all.</p>
<p>Contrary to perhaps what we thought in the honeymoon phase of learning “agile” it isn’t a magic silver bullet for curing all ills of software engineering. However, agile processes do stand in stark contrast to the traditional “waterfall” model of software enginering. A strongly waterfall process is very hard to change, which is precisely why they’re such a bad idea. Perhaps we can summarise the essence of agile as <em>“finding engineering processes and practises that are able to evolve and suit the specific needs of the team, product and customers”</em>. Being able to change matters, being stuck is awful.</p>
<p><em>This post originally appeared on my personal blog <a href="http://www.michaelfoord.co.uk/2018/02/a-very-short-love-letter-to-agile.html">A Love Letter to Agile on Unpolished Musings</a>.</em></p>Michael FoordThe Role of Abstractions in Software Engineering2018-07-16T00:00:00+00:002018-07-16T00:00:00+00:00https://agileabstractions.com/Abstractions<p><img src="/images/concrete-apple.jpg" alt="Abstract Representation of a Concrete Apple" /></p>
<p>This is a video and text of a lightning talk, a five minute presentation, given at PyCon US 2018 in Cleveland. The image is an abstract representation of a concrete apple.</p>
<ul>
<li><a href="https://youtu.be/c-I0md_3fbQ?t=255">The Role of Abstractions Lightning Talk</a></li>
</ul>
<p>This is an abstract talk. There isn’t time to give examples but I hope that the application to the day to day challenges of the practise of software engineering is clear. The only theory worth a damn is the theory of the practise. This is a talk about the role of abstractions in software engineering.</p>
<p>Programming is all about the use of abstractions. We often say that the fundamental language spoken by the machine is ones and zeros. Binary. This isn’t true. Ones and zeroes are an abstract representation of the fundamental operation of computers. It’s a way of representing what central processors do in a way that can be understood by people.</p>
<p>The actual language spoken by computers is the electromagnetic dance across wires and etched silicon, choreographed by the beating of a quartz crystal at the heart of the machine.</p>
<p>Ones and zeroes are a representation of that dance, understandable by humans in order for us to reason about the behaviour of the system.</p>
<p>That’s a very low level abstraction. Very close to the actual operation of computers, but very hard to work with. The next step up is assembly language where we use mnemonics, symbolic instructions like JMP for jump, to represent these patterns of ones and zeroes. We can also use human recognisable labels for memory locations instead of numbers and allow the assembler to calculate offsets for us. Much easier.</p>
<p>Next we have languages like C and then right at the very top we have Python where each construct, a print statement for example, may correspond to as many as millions of the lowest level operations.</p>
<p>Computer programming is communication in two directions. Programming provides a language the computer understands, and is able to execute deterministically, whilst also communicating with humans so they can conceptualise the behaviour of the system. A programming language is a set of conceptual tools to facilitate that communication in both directions.</p>
<p>The art and craft of software engineering is taking the conceptual tools that programming languages provide and using them to solve real world problems. This is the difference between science and engineering. Science is the theory, engineering is the application.</p>
<p>In order to be able to do this we have to have an understanding of the problem domain. We conceptualise it. We think about it. Software is easy to understand and maintain when the abstractions you build map well to the problem domain. If the way you think about the problem is close to the way you think about your software then you have to do less mental translation between the problem and your code.</p>
<p>Joel Spolsky talks about the law of leaky abstractions. Any abstraction that maps to lower level operations in the system will leak. At some point something will go wrong and you will only be able to fix it by understanding the lower level operations too.</p>
<p>I’ve heard it said, and it rings true, that a good programmer can hold about ten thousand lines of code in their head. So if your system is less than ten thousand lines of code, even if it’s terrible code, you don’t need to build higher level building blocks to hold it in your head.</p>
<p>An all too common situation is that a system becomes too complex to reason about, so an engineer decides to create abstractions to simplify how they think. So they create black boxes, abstractions, in which to place the complexity. These type of abstractions conceal complexity. So now you don’t have to look at the mess you just made.</p>
<p>You can reason about your system with your abstractions, but in order to understand the actual behaviour (at a lower level) you need to go digging in all that dirt.</p>
<p>Instead of concealing complexity a good abstraction will explain and point you to the lower level operations. Good abstractions simplify and reveal complexity rather than concealing it.</p>
<p>We can also use this kind of reasoning to think about product and system design. What user experience are you providing, what’s the user story? Your users also think about the problem domain using conceptual tools. The closer the abstractions your software presents to your user map to the way they already think about the problem the easier your software will be to use.</p>
<p>And here we come full circle. If the way you build your software maps well to the problem domain then it will be easy to reason about and maintain. If the abstractions you present to the user map well to the problem domain then it will be easier for your users to think within your system and it will be more intuitive to use.</p>
<p>So abstractions matter. They’re the raw stuff of our world.</p>
<p><em>This post originally appeared on my personal blog <a href="http://www.michaelfoord.co.uk/2018/05/the-role-of-abstractions-in-software.html">Abstractions on Unpolished Musings</a>.</em></p>Michael FoordHello World2018-07-11T00:00:00+00:002018-07-11T00:00:00+00:00https://agileabstractions.com/Hello-World<p><img src="/images/bumblebee.jpg" alt="As Busy as a Bee" /></p>
<p>It feels funny to be writing a “Hello World” blog entry in a new technical blog so far into my adventures with Python. January 2005 and my <a href="http://www.voidspace.org.uk/python/weblog/arch_d7_2005_01_22.shtml#e1">first entry in my Python technical blog</a>, which marked the very early days of me discovering Python and falling in love with it, doesn’t seem so very long ago.</p>
<p>This was only a year or so before I started my first programming job, with a small London startup called Resolver Systems. We were building a Windows desktop spreadsheet application, using IronPython, with Python embedded as the calculation engine for the spreadsheet. I can’t find a blog entry when I first started working with the Resolver team, but in December 2006 I wrote a post <a href="http://www.voidspace.org.uk/python/weblog/arch_d7_2006_12_02.shtml#e573">Happy Birthday Resolver</a>.</p>
<p>Since then I’ve had many more adventures including working freelance building web applications with Silverlight and IronPython in the browser, web application development with Django for Canonical, Go development working on a devops tool called Juju and working for Red Hat Ansible as a test engineer.</p>
<p>Python and the Python community has been very good to me in providing me with friendship, intellectual stimulation, a passion for engineering and a career. My involvement in the community included running Planet Python for many years, helping maintain the <a href="http://www.python.org">python.org</a> website, becoming a Python core developer and helping maintain unittest whilst writing and contributing <a href="https://docs.python.org/3/library/unittest.mock.html">mock</a> to the Python standard library plus at various points helping organise and speaking at all of PyCon in the US, EuroPython and PyCon UK. I was organiser and compere of the Python Language Summit from 2010 to 2014 and the Dynamic Languages VM Summit at PyCon 2011. I’ve lost track of the various conferences I’ve spoken about; spanning .NET, Python specific conferences and general programming like the ACCU conference. I’ve keynoted at PyCon India and PyCon New Zealand, probably the greatest privileges of my career so far.</p>
<p><img src="/images/belfast.jpg" alt="Belfast 2006" /></p>
<p>I’m not saying any of this to boast (mostly), many of my contemporaries and those who are newer to the Python and programming communities have found as much of a passion and a sense of belonging in the Python community as I found. It’s fun to reminisce because it’s been such an enjoyable trip and one that’s far from over.</p>
<p>Alongside that, since 2011, I’ve done Python training on behalf of <a href="https://www.dabeaz.com/">David Beazley</a>. Teaching Python, both the introduction course and the super-advanced Python Mastery course, has been the most fun thing I’ve done professionally with Python. This is one of the reasons I’ve decided it’s time to branch out as a freelance Python programmer, trainer, contractor and consultant.</p>
<p>This blog entry is both a “Hello World” for the blog and for my new venture <a href="https://agileabstractions.com">Agile Abstractions</a>. I’m available for contract work, specialising in the automated end-to-end testing of systems.</p>
<p>The training courses I offer are listed here:</p>
<ul>
<li><a href="/training/">Python and Testing Training Courses</a></li>
</ul>
<p>For custom training packages or any enquiries contact me on <a href="mailto:michael@python.org">michael@python.org</a>.</p>
<p>If you’re at EuroPython in Edinburgh this year, or PyCon UK in Cardiff, then hopefully I’ll see you there!</p>
<p><img src="/images/pycon2018.jpg" alt="PyCon 2018" /></p>
<p>This website is built with <a href="https://jekyllrb.com/">Jekyll</a> using the open source <a href="https://github.com/barryclark/jekyll-now">Jekyll Now</a> and hosted on <a href="https://pages.github.com/">Github Pages</a>. It’s a lovely and simple workflow for geeks to build and host websites that include a blog. It reminds me of the heady days of 2006 and my static site generator <a href="http://www.voidspace.org.uk/python/rest2web/">rest2web</a>.</p>Michael Foord