<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Tom Oram on Medium]]></title>
        <description><![CDATA[Stories by Tom Oram on Medium]]></description>
        <link>https://medium.com/@tom-oram?source=rss-8b62695f2784------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*662WyGiPyeLY02HbmeXBcw.jpeg</url>
            <title>Stories by Tom Oram on Medium</title>
            <link>https://medium.com/@tom-oram?source=rss-8b62695f2784------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 00:17:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@tom-oram/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Introducing Painless Pipelines]]></title>
            <link>https://medium.com/cloudnative-ly/introducing-painless-pipelines-23b01f1bb490?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/23b01f1bb490</guid>
            <category><![CDATA[continuous-delivery]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[pipelines-as-code]]></category>
            <category><![CDATA[continuous-deployment]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Mon, 24 Jul 2023 09:48:01 GMT</pubDate>
            <atom:updated>2023-07-24T09:48:01.340Z</atom:updated>
            <content:encoded><![CDATA[<p>Continuous Delivery pipelines exist to make the software development process easier. They aim to improve flow and simplify the process of getting ideas to production. They remove many of the <em>pains</em> of doing this process manually. However, depending on how they are implemented, they can introduce new <em>pains</em> within the team. I have been considering what can cause these new pains and how to avoid them.</p><figure><img alt="Summary image of the pain, modes of interactions, principles and practices discussed in this article." src="https://cdn-images-1.medium.com/max/1024/1*0cg8JbPF_EDxvcfQLoHi4g.png" /></figure><h3>What is a Painless Pipeline?</h3><p>A painless pipeline does not create any new <em>pains</em>. It delivers the promised benefits of CD pipelines without making additional cognitive load for the developers on the team.</p><h4>Typical Pipeline Pains</h4><p>Some of the common pains I have seen in pipelines are:</p><ul><li><strong>Hard to debug</strong>: “<em>Why did it fail?”</em></li><li><strong>Hard to make changes</strong>: you have to keep pushing fixes until it works</li><li><strong>Slow feedback</strong>: wait minutes or more to see if a config change worked</li></ul><p>Often, these pains are created by situations where pipelines are developed either by <strong>focusing on only the happy path</strong> (with a <em>“just get it done”</em> mindset) or were <strong>created by different people</strong> (e.g. DevOps engineers, contractors, consultants).</p><h3>Modes of Interaction</h3><p>There are three different ways a software team interacts with a pipeline. These are:</p><ul><li>When it is <strong>green</strong> (all jobs have successfully passed)</li><li>When it is <strong>red</strong> (a job has failed)</li><li>When a pipeline change is <strong>required</strong> (e.g. adding a new job)</li></ul><p>Let’s consider each in turn.</p><h4>When it is green</h4><p>When a pipeline is green, there is generally little interaction with it. It is usually a sign that everything is well and the team can continue their work.</p><p>The only problem that might occur with a green pipeline is when something is actually broken; a pipeline that tells you everything is okay when a failure has happened behind the scenes is creating pain, so your pipelines should always aim to fail if there is a problem.</p><h4>When it is red</h4><p>When a pipeline is red, then some action needs to be taken. If the pipeline clearly points to the problem and how to fix it, then it is helping us. However, if the failure sends us off on a journey of searching and confusion, it creates more pain.</p><p>There are different types of failure that can cause your pipelines to turn red. These include:</p><ol><li>Genuine failures</li><li>Environment failures</li><li>Transient failures</li></ol><p>In the case of a<em> genuine failure</em>, it helps if it clearly tells us what went wrong. The same applies to <em>environmental failures; however</em>, this may need to be supported with additional tooling outside of the pipeline (dashboards, alerts, etc.). Finally, we want to try and stamp out <em>transient failures</em> altogether; if we have any jobs that <em>“just fail sometimes”</em>, they need to be treated as broken and fixed.</p><h4>When pipeline changes are being made</h4><p>The final interaction we have with our pipelines is updating them — when we need to add to them, change them, or fix them. If making these changes is unpredictable and frustrating, it is another pain source. An example is when you need to make a change but don’t know if it has worked until you have committed it, pushed it, and waited for the pipeline to run it — only for it to fail with a trivial mistake.</p><p>For pipeline changes to be painless, the config should be easy to work with and quick to test.</p><h3>Making Pipelines Painless</h3><p>To make your pipelines painless, I have come up with four principles, and four practices to help you realise those principles. How you realise these might vary depending on your tools, but I hope the ideas apply to them all.</p><h4>The Principles</h4><ul><li>Treat your pipeline as a software product</li><li>Design your pipelines to be easy to use</li><li>Failure is a feature</li><li>The developers are also the users</li></ul><h4>The Practices</h4><ul><li>Be <strong>defensive</strong></li><li>Be <strong>atomic</strong></li><li>Be <strong>expressive</strong></li><li>Be <strong>reusable</strong></li></ul><p>Now, let’s look at each of these in turn.</p><h3>The Principles</h3><p>The principles are a mindset. They don’t aim to tell you how to do anything, but they guide the decisions you make.</p><h4>Treat your pipeline as a software product</h4><p>Too often, pipelines are developed with less care than the thing they are deploying. They are cobbled together until they work, then forgotten about until they break or need updating. There are a few reasons for this; for example, it could be that the application developers do not have expertise with these tools, or it could be that there is pressure to deliver the user-facing features faster. Often, a “DevOps” engineer or team is brought in to create them, but these creates silos and reduce team ownership.</p><p>This principle is about treating your pipeline projects like your software projects. Design them well, refactor them, test them, and ensure that they are implemented to a standard.</p><h4>Design your pipelines to be easy to use</h4><p>The people who interact with the pipeline (primarily the development team) are the pipeline users. Make the pipeline easy and informative to use; make it tell you what has failed, what is wrong, and how to fix it.</p><h4>Failure is a feature</h4><p>Pipelines often have been built with a focus on the happy path. They work well when green but don’t provide a great user experience when they fail. However, failure is an important feature of a pipeline; it is the one we interact with the most so we need it to help us. Make failures helpful and informative.</p><h4>The developers are also the users</h4><p>One unique thing about pipelines is that the developers who build them are likely also the users. That means that changing and developing them is part of the users&#39; experience. Therefore, we should treat the ability to maintain the pipeline as one of its features. Making changes should be easy, predictable, and as safe as possible.</p><h3>The Practices</h3><p>The principles above provide an idea of how we should treat our pipelines. The following practices aim to turn them into concrete actions.</p><h4>Be Defensive</h4><p><strong>When the pipeline performs a task, it should explicitly check for any problems and report clear errors if anything is incorrect.</strong></p><p>This practice helps us when we want to make changes to the pipeline by quickly informing us what went wrong. A pipeline should give a descriptive error when the task fails. Here are some examples of why a pipeline might fail:</p><ul><li><strong>An error in an artifact</strong><br><em>e.g. the code is broken</em></li><li><strong>An environment error<br></strong><em>e.g. the deployment environment is broken</em></li><li><strong>A pipeline config/scripting error</strong><br><em>e.g. you forgot to provide a required environment variable</em></li></ul><p>When the pipeline fails for one of these reasons, the error should help you resolve the issue. It should do one of the following:</p><ul><li><strong>Describe the problem</strong><br><em>e.g. “The required AWS_ACCESS_KEY environment variable is missing.”</em></li><li><strong>Redirect you to a place where you can get more information</strong><br><em>e.g. “The production environment is not reachable; please check </em><a href="http://monitoring-dashboard.com/"><em>http://monitoring-dashboard.com</em></a><em>”</em></li></ul><p><strong>Example:</strong></p><p>In this example, we have a bash script as part of the pipeline job which substitutes some values into a Google AppEngine <em>app.yaml</em>.</p><pre>#!/usr/bin/env bash<br><br>set -euo pipefail<br># …<br>sed &quot;s/#DB_HOST#/${DB_HOST}/g&quot; app.yaml.tpl | \<br> sed &quot;s/#DB_USER#/${DB_USER}/g&quot; | \<br> sed &quot;s/#DB_PASSWORD#/${DB_PASSWORD}/g&quot; | \<br> sed &quot;s/#DB_DATABASE#/${DB_DATABASE}/g&quot; &gt;app.yaml<br># …<br><br># gcloud command to deploy the app</pre><p>When pushed, the pipeline reports the following error:</p><blockquote>500: An unknown error occurred</blockquote><p>Thanks Google!</p><p>Eventually, we discovered that the app.yaml.tpl file had an extra #<strong>PROJECT_ID#</strong> placeholder that had not been substituted. We could have saved time searching for this issue if the script had also checked for any placeholders that had not been replaced and reported an error like so:</p><blockquote>Error:<br>app.yaml contains an unsubstituted template variable #PROJECT_ID#</blockquote><h4>Be Atomic</h4><p>Each step should be easy to run in isolation when given a set of inputs and expected outputs.</p><ul><li>Each step should be a script, program, or configuration that can be run locally on a developer&#39;s machine.</li><li>Each step should have stubs, mocks, or whatever is required to allow it to be run and verified locally (a “unit test”).</li><li>All steps can be run as a part of a test suite.</li><li>If a step cannot be run locally, it should be run as a stand-alone step in a separate test pipeline.</li></ul><p><strong>Example:</strong></p><pre>$ export DB_HOST=localhost<br>$ export DB_USER=appuser<br>$ export DB_PASSWORD=secretsecret<br>$ export DB_DATABASE=customers<br>$ ./substitute-templates — template app.yaml.tpl — output app.yaml — var-source environment</pre><pre>$ ./run-pipeline-unit-tests<br>Tag and release tests<br>✅ creating git tag succeeds<br>✅ creating git tag fails when tag already exists<br>✅ creating git tag fails when tag has incorrect format AppEngine Deploy tests<br>✅ substitute template vars in app.yaml<br>✅ substitute template vars in app.yaml fails when env var is missing<br>❌ substitute template vars in app.yaml fails when env var is not substituted</pre><h4>Be Expressive</h4><p>Use languages and tools that make coding and error reporting easy and clear.</p><ul><li>Use an appropriate programming language.<br><em>i.e. don’t resort to bash or PowerShell because it’s quick.</em></li><li>Create/use tools that can be reused.<br><em>e.g. a templating tool that performs validation.</em></li><li>Practice Test-Driven Development (TDD).</li></ul><p><strong>Example:</strong></p><pre>step:<br> name: prepare app.yaml<br> type: shell<br> command: |<br> #!/usr/bin/env bash<br>   set -euo pipefail# Substitute env vars<br>   sed &quot;s/#DB_HOST#/${DB_HOST}/g&quot; app.yaml.tpl | \<br>     sed &quot;s/#DB_USER#/${DB_USER}/g&quot; | \<br>     sed &quot;s/#DB_PASSWORD#/${DB_PASSWORD}/g&quot; | \<br>     sed &quot;s/#DB_DATABASE#/${DB_DATABASE}/g&quot; &gt;app.yaml<br>   # Check for unsubstituted env vars<br>   grep -i &#39;#[A-Z]*#&#39; app.yaml</pre><pre>step:<br> name: prepare app.yaml<br> type: shell<br> command: python substitute-templates.py — template app.yaml.tpl — output app.yaml — var-source environment</pre><h4>Be Reusable</h4><p>Invest in building tools you can use again.</p><ul><li>If you are investing more time in building tools right, build them to be reused.</li><li>Reuse your tools in different steps, pipelines and projects.</li><li>Make them available to others (via open source if possible).</li></ul><p><strong>Example:</strong></p><pre>step:<br> name: prepare app.yaml<br> type: substitute-templates<br> options:<br> template-file: app.yaml.tpl<br> output: app.yaml<br> var-source: environment</pre><h3>Conclusion</h3><p>Your pipelines are a critical part of your development process, therefore, treat them as you would treat your software projects. They should not be a string of minimum-viable-scripts, but rather tools that support the people interacting with them.</p><p>The things I have presented in this article are not the complete picture, there are other important things in pipelines, such as ensuring that the sample artifacts are used throughout, making sure pipelines don’t take too long, and ensuring that the jobs are idempotent. However, the practices and principles I have presented should be added on top of these common practices to enhance the user experience.</p><p>Also, pipelines alone do not solve all the problems. Having good observability (including logs, dashboards, alerts, and traces where appropriate), will also contribute to the painless experience.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=23b01f1bb490" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/introducing-painless-pipelines-23b01f1bb490">Introducing Painless Pipelines</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Event-Driven Architectures (EDAs) vs Event Sourcing]]></title>
            <link>https://medium.com/cloudnative-ly/event-driven-architectures-edas-vs-event-sourcing-c8582578e87?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/c8582578e87</guid>
            <category><![CDATA[software-design]]></category>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[event-sourcing]]></category>
            <category><![CDATA[event-driven-architecture]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Wed, 19 Jul 2023 09:07:11 GMT</pubDate>
            <atom:updated>2023-07-19T09:07:11.486Z</atom:updated>
            <content:encoded><![CDATA[<p>Event Sourcing and Event-Driven Architecture often appear together; many blog articles mix the two and some books introduce them in the same section, but they are two different things. They can be used together, and it is often appealing to do so because both are centred around thinking in terms of <em>events</em>. However, both patterns are non-trivial, so it is essential that we clearly understand the differences so we can design the complicated systems that use them successfully.</p><h3>Basic Application</h3><p>Before introducing the concepts, let’s consider a simple scenario to extend with these patterns. A user interacts with a basic application, which stores and retrieves data from a database. Admittedly, most applications are significantly more complicated than this in the modern age, but this is a familiar scenario and the perfect starting point. We program the <em>business logic</em> in the application and use the database to store the <strong>current state of the entities in the system</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/235/1*aM6s9dIKUMXcDUbAxM13Ew.png" /><figcaption>Application with a database</figcaption></figure><h3>Event-Driven Architecture</h3><p>With Event-Driven Architectures, we use events to <strong>communicate</strong> change between system parts. When an event occurs in some part of the system, we publish it so the other components can choose to react. This pattern can be used within a monolithic application using the <a href="https://refactoring.guru/design-patterns/observer">observer design pattern</a>; however, in modern systems, this is often distributed between in-dependent services using message queues.</p><p>Event-Driven Architectures have to embrace <em>asynchronicity</em> and <em>eventual consistency</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*iQQ1Oa4RnVcXrUHYJjnZ6w.png" /><figcaption>Event-Driven Application</figcaption></figure><h3>Event Sourcing</h3><p>Event Sourcing is a <strong>persistence</strong> pattern. Instead of having a database that stores the current state of the entities, we have an <em>immutable event log</em> that stores the history of all the changes made. The event log is the <em>single source of truth. T</em>he current state is obtained by replaying the events in the application.</p><p>The event log provides an <em>audit trail</em> and the ability to <em>construct the state at any point in history</em>.</p><p>For more details on Event Sourcing, see my previous article, <a href="https://cloudnative.ly/what-is-event-sourcing-d201ed740451">What is Event Sourcing</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/197/1*5l4EviVuygzim9cq_Dllqg.png" /><figcaption>Event Sourced Application</figcaption></figure><h3>Using Event Sourcing with Event-Driven Architectures</h3><p>Event-Driven Architectures and Event Sourcing are two different things; the former is a <strong>communication pattern</strong> while the latter is a <strong>persistent state pattern</strong>. The only thing these two things have in common is <em>events</em>. However, the fact that they are both centred around events makes them both appealing to people building systems based on events.</p><p>However, there is an important question…</p><h4><strong>Are event-sourced events and event-driven events the same?</strong></h4><p>The default answer here should be <strong>“No”</strong>; here’s why:</p><p>Considering the pure concept of Event Sourcing, your event log is your database; the only service that reads your database is the event-sourced service. Its implementation, structure, and existence are purely an implementation of your service. On the other hand, the events published by a service are part of its public interface; consuming services are coupled to the events and their structure. When you expose the event-sourced events, you make them part of your public interface. In addition, you may only want to publish some of your events or some part of their content; you want to provide a limited subset. Conversely, you may also want to publish additional events that are not part of the state.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/685/1*MUv8bHDsp4nmRYbVNABCTg.png" /><figcaption>Event-Driven and Event Sourced Architecture (different events)</figcaption></figure><h4>The non-default answer is “It depends”</h4><p>Sometimes, it is too convenient to publish the event-sourced events to other services; you might find that when keeping them separate, you have to create two event datatypes for every new event. When this is the case, there is probably a tight relationship between the services publishing the events and those consuming them. They are likely local components of the same service, developed within the same team. If they are not, then this decision should be made very cautiously.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/732/1*ZmqNx0KDs5eL6G2HzCaY3w.png" /></figure><h3>Command-Query Responsibility Segregation Architecture (CQRS)</h3><p>One pattern that is bound to come up when talking about distributed and event-sourced systems is Command-Query Responsibility Segregation (CQRS). CQRS is a detailed pattern, although I’m skipping a lot of that detail in this example; I’m simply separating the write side (where commands are sent) of the model from the read side (where queries are made). It also does not need to be used with events (although they are an excellent fit). This pattern optimises the read model for high-performance reads at the cost of eventual consistency. It is excellent for systems with a high ratio of reads to writes. For example, a user may make a lot of requests while browsing products on an online store and then make just one purchase request at the end. CQRS is not a good fit if you have a 1:1 reading and writing ratio; it has probably only been added to mask slow performance on the write side by acting as a read cache.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tPsM-CRBKIwWw-JUjQoYmQ.png" /><figcaption>Command-Query Responsibility Segregation (CQRS)</figcaption></figure><p>For this example, I have used an event-sourced write service and an event-driven read service. This whole thing could be one service in a larger system. A single team might be building it as a single service as one business component in the system. In this case, the read database could simply be a viewable <em>projection</em> of the event log; the events that drive the read service are the events in the event log.</p><p>However, this model could also be distributed further. The writing service is one application built by one team, and the read service is a consumer service created by another team. In this case, it makes sense for the events to be different, curated ones.</p><h4>Writes might not require state</h4><p>One of the key points in the previous example is that the write service fetches the state from the event log. This is very important in a system where state changes depend on the current state. However, you may have a system where the commands generate events without referencing the current state. In these cases, the write service never reads back from the event log. The write service generates and publishes the event, and then the read service consumes it. From that aspect, the read service is event-driven. However, the event log is still the <em>single source of truth</em>, so we could also argue that it is event-sourced.</p><p>This pattern is more straightforward with a tool like Kafka as the event queue, because it can also persist the streams and behave as the log.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/611/1*04V0ZLi4qmmQlqw84_s1Ig.png" /><figcaption>CQRS application without writer state</figcaption></figure><h3>Summary</h3><p>Event-Driven Architectures are a communication pattern, whereas Event Sourcing is a persistent state pattern. When looked at independently, they are two very different things, but combining them in different ways can blur the distinctions. Also, both patterns bring advantages, but at the cost of being more complicated. Finally, the locality of the services that consume your events affects which events you should expose.</p><p>My final suggestions are:</p><ul><li>Make sure you understand each pattern in isolation before combining them.</li><li>Consider carefully if they are suitable patterns for your problem.</li><li>Only expose your event-sourced events if the consuming service is very local. Otherwise, publish specific events for external consumption.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c8582578e87" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/event-driven-architectures-edas-vs-event-sourcing-c8582578e87">Event-Driven Architectures (EDAs) vs Event Sourcing</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Better Ways to Implement Single-Method Classes]]></title>
            <link>https://medium.com/cloudnative-ly/better-ways-to-implement-single-method-classes-b737c6c32deb?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/b737c6c32deb</guid>
            <category><![CDATA[sofware-development]]></category>
            <category><![CDATA[object-oriented]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[functions-in-python]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Mon, 03 Jul 2023 08:22:12 GMT</pubDate>
            <atom:updated>2023-07-03T08:22:12.225Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PelNLNDmf7hcb4MQ.png" /><figcaption>/imagine a class with a single method rewritten as a higher-order function</figcaption></figure><p>Suppose you’re coming to a programming language which allows you to program in multiple paradigms, like Python or TypeScript, but you have come from an object-oriented programming (OOP) background. In that case, you might choose to continue building your software in the OOP way you love. Writing code this way is perfectly reasonable, but you might create unnecessary boilerplate code if you insist on using the class keyword for everything. I want to show how you can rewrite a common type of class differently, reducing the amount of typing you have to do and making the code more straightforward to understand.</p><h3>Single Method Classes</h3><p>The type of class I’m talking about is a single-method class. These classes represent a single action, but they might wrap up some state or dependencies which the method will use when invoked.</p><p>Let’s look at some examples:</p><h4>Simple Action</h4><p>The simplest form is a function with no dependencies wrapped in a class. The only reason these classes exist is that the language does not support functions outside of classes. Java introduced the Runnable interface for this exact reason.</p><pre>class Adder:<br>    def calculate(self, a: int, b: int) -&gt; int:<br>        return a + b</pre><p>Here we can move the class out of the function altogether.</p><pre>def add(a: int, b: int) -&gt; int:<br>    return a + b</pre><p>You might think you have lost the ability to define an interface that your Adder class implemented so that you supply alternative implementations to consumers — for example, a <em>Calculator</em> interface. You may not be able to create an interface (or a Protocol in the Python world) when you only have a function; however, you can still define an abstraction by creating an alias to a callable type.</p><pre>Calculator = Callable[[int, int], int]</pre><h4>Dependency Injection</h4><p>Another example of a class with a single method is one where we use constructor injection to provide dependencies for the method. This enables us to pass only the instance to where we need it without having to pass the dependencies too. Here’s an example of such a class.</p><pre>class OrderCreator:<br>    def __init__(self, order_repository: OrderRepository, email_sender: EmailSender):<br>        self._order_repository = order_repository,<br>        self._email_sender = email_sender<br><br>    def create_order(self, customer: Customer, items: list[Items]) -&gt; None:<br>        order_id = OrderID.generate()<br>        order = Order(order_id, items)<br>        self._order_repository.save(order)<br>        confirmation_email = Email(to=customer, subject=f&quot;Thank you for your order ${order_id}&quot;)<br>        self._email_sender.send(confirmation_email)</pre><p>We would then use it like this:</p><pre>order_creator = OrderCreator(some_order_repository, some_email_sender)<br><br># at another code location<br>order_creator.create_order(logged_in_customer, cart.get_items())</pre><p>We can create this pattern by creating a constructor function which returns a new closure function with the dependencies baked in. We can again use a type alias to define a meaningful named type.</p><pre>CreateOrder = Callable[[Customer, list[Items]], None]<br><br>def new_order_creator(order_repository: OrderRepository, email_sender: EmailSender) -&gt; CreateOrder:<br>    def create_order(customer: Customer, items: list[Items]) -&gt; None:<br>        order_id = OrderID.generate()<br>        order = Order(order_id, items)<br>        order_repository.save(order)<br>        confirmation_email = Email(to=customer, subject=f&quot;We have recieved your order {order_id}&quot;)<br>        email_sender.send(confirmation_email)<br>    return create_order</pre><p>We would then use it like this:</p><pre>create_order = new_order_creator(some_order_repository, some_email_sender)<br><br># at another code location<br>create_order(logged_in_customer, cart.get_items())</pre><h4>Deferred Dependencies</h4><p>This pattern is the same as the previous example but used the other way around. In this case, we inject the values in the constructor but provide some dependencies when we invoke the method. Let’s see an example:</p><pre>class Email:<br>    def __init__(self, to: str, subject: str, body: str):<br>        self._to = to<br>        self._subject = subject<br>        self._body = body<br><br>    def send(self, sender: EmailSender) -&gt; None:<br>        sender.send(self._to, self._subject, self._body)</pre><p>We would then use it like this:</p><pre>email = Email(<br>      to=customer.email_address,<br>      subject=f&quot;We have received your order {order_id}&quot;,<br>      body=f&quot;&quot;&quot;<br>      Dear {customer.name}<br>      Thank you for your order!<br>      &quot;&quot;&quot;<br>  )<br><br># at another code location<br>email.send(some_email_sender)</pre><p>Because the pattern is the same as the previous one, the classless version follows the same pattern:</p><pre>SendEmail = Callable[[EmailSender], None]<br><br>def create_email(to: str, subject: str, body: str) -&gt; SendEmail:<br>    def send(sender: EmailSender) -&gt; None:<br>        sender.send(to, subject, body)<br>    return send</pre><p>We would then use it like this:</p><pre>send_email = create_email(<br>      to=customer.email_address,<br>      subject=f&quot;We have received your order {order_id}&quot;,<br>      body=f&quot;&quot;&quot;<br>      Dear {customer.name},<br>      Thank you for your order!<br>      &quot;&quot;&quot;<br>  )<br><br># at another code location<br>send_email(some_email_sender)</pre><h3>Summary</h3><p>If you create classes with a single method, you might be better off just creating a function. Using functions might seem like you are not doing OOP, but the model remains the same; an instance wraps a behaviour with a single way to invoke it. Also, you can use type aliases to give these functions named abstractions, which you can use for type signature, descriptiveness and communication. The command classes can be necessary for object-oriented languages because there is no better way to implement them.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b737c6c32deb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/better-ways-to-implement-single-method-classes-b737c6c32deb">Better Ways to Implement Single-Method Classes</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Designing Software Architectures For People in 2023]]></title>
            <link>https://medium.com/cloudnative-ly/designing-software-architectures-for-people-in-2023-b83d394734ce?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/b83d394734ce</guid>
            <category><![CDATA[software-team]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[team-topologies]]></category>
            <category><![CDATA[conways-law]]></category>
            <category><![CDATA[software-architecture]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Mon, 26 Jun 2023 08:38:28 GMT</pubDate>
            <atom:updated>2023-06-26T08:38:28.948Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dzdX6mbAtT9_SH8r.png" /></figure><p>Five years ago I wrote the article <a href="https://cloudnative.ly/designing-microservice-architectures-for-people-fcb4fb92397">Designing Microservice Architectures for People</a>. Today I want to reflect on the content and see how it has aged. In the previous article, I put the emphasis on microservices. I also presented three ideas that would bring the focus to aligning your architecture with your organisation structure: <em>The Single Responsibility Principle</em>, <em>Bounded Contexts</em> and <em>Conway’s Law</em>. Let’s reflect on the ideas I presented.</p><h3>The Focus on Microservices</h3><p>In the previous article, I stated that microservice architectures were everywhere at the time. I don’t think that has changed, but we’ve stopped talking about them so much. Cloud platforms and serverless offerings seem to have detracted from the term microservices, even though the systems built using these technologies are often still microservices architectures, just implemented with different tools.</p><p>Recently, we’ve also seen talk from prominent companies about them <a href="https://www.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-video-monitoring-service-and-reducing-costs-by-90">migrating from distributed systems back to monoliths</a>. As a result, monoliths are getting a little bit of a buzz again. I’m sure we’re not going to move to an era when everything is a monolith by default, but I do think we’re entering an era where the stigma of <em>monoliths</em> has gone, and they will more commonly be considered a viable option for parts of the systems we build.</p><p>In the previous article, I focussed on microservices because I was trying to address a problem which I was finding widespread — teams building “microservices” because of the hype, but ending up creating tightly-coupled architectures; or what we affectionately call <em>distributed monoliths</em>. However, everything I covered still applies in these other types of systems; in fact, most of the thinking around the ideas I presented pre-exists microservices altogether. From this perspective, I think that what I presented would still serve well with the term microservices wholly removed.</p><h3>The Three Ideas</h3><p>There is very little to say about the three ideas I presented. Their usefulness and importance today are no different from how it was five years ago. They should be applied when building software systems; whether monolithic, cloud-based or microservices.</p><p>That said, there has been some interesting additional thinking that has come out since my previous article…</p><h3>Team Topologies</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/334/0*P-PLODHKWtFdDR6B.jpg" /></figure><p>In 2019, Matthew Skelton and Manuel Pais published their book <a href="https://teamtopologies.com/">Team Topologies</a>. Like my original article, Team Topologies emphasises a team-first approach to software architecture. This idea is not new; for example, Michael Nygard’s book Release It! was published in 2007 and says “<em>Team assignments are the first draft of the architecture.” — </em>Matthew and Manuel reference this quote in their book.</p><blockquote>Your early decisions make the biggest impact on the eventual shape of your system. The earliest decisions you make can be the hardest ones to reverse later. These early decisions about the system boundary and decomposition into subsystems get crystallized into the team structure, funding allocation, program management structure, and even time-sheet codes. Team assignments are the first draft of the architecture. (See <em>​Conway’s Law​.</em>)</blockquote><blockquote>Release It!<br>Michael Nygard 2007</blockquote><p>However, Team Topologies explicitly calls out Fast Flow as the output you want from your optimised team and software architectures. The book is based on the four <em>team types</em> it presents (<a href="https://teamtopologies.com/key-concepts"><em>stream-aligned</em>, <em>platform</em>, <em>enabling</em> and <em>complicated subsystem</em></a>). It suggests Conway&#39;s Law as one of the driving <em>forces</em> in designing teams, as does my original article and Michael’s book from back in 2007.</p><p>This set of four <em>team types</em> (and the<em> interaction modes</em> that go with them) is an incredibly useful tool for designing people-centric software. Team Topologies is a must-have when designing software architectures for people. However, the most interesting piece for me was that it brought the idea of Cognitive Load into the equation.</p><p>The Team Topologies book shows how we don’t want to just line software boundaries up with teams, but also we want to ensure that teams are designed and sized so that the cognitive load required to do work is comfortable. By managing the cognitive load in the team, not only does work <em>flow</em> through the value stream query, and individuals and the team also enter <a href="https://www.medicalnewstoday.com/articles/flow-state#characteristics"><em>flow states</em></a> more easily. Woody Zuill refers to the combination of these three types of flow as <a href="https://www.youtube.com/watch?v=28S4CVkYhWA"><strong>Flow++</strong></a>.</p><h3>The rise of “Socio-technical”</h3><p>This idea that building software is less dominated by the technical and heavily informed by the social is becoming more widespread. As a result, the term Socio-technical is becoming more prevalent.</p><blockquote>Socio-technical theory has at its core the idea that the design and performance of any organisational system can only be understood and improved if both ‘social’ and ‘technical’ aspects are brought together and treated as interdependent parts of a complex system.</blockquote><blockquote>Source: <a href="https://business.leeds.ac.uk/research-stc/doc/socio-technical-systems-theory">https://business.leeds.ac.uk/research-stc/doc/socio-technical-systems-theory</a></blockquote><p>The term is not new; it was coined in the World War II era, but it has only recently become more commonplace when discussing software. If we see the software architecture and the social constructs in the organisation as two parts of the same system, then work will flow more naturally.</p><p>As this thinking evolves, some exciting ideas are being developed; for example, <a href="https://medium.com/u/d012fdeb34b0">Nick Tune</a> has published some <a href="https://medium.com/nick-tune-tech-strategy-blog/an-introduction-to-sociotechnical-architecture-patterns-ea64a75c2aaf">socio-technical architecture patterns</a> and an <a href="https://www.manning.com/books/architecture-modernization">upcoming book</a> on the topic.</p><h3>Conclusion</h3><p>The ideas behind improving the ways that large organisations are building software are still evolving and improving. What I have taken away from this reflection, is that tools, patterns, architectures and methodologies come and go, but solid underlying principles persist. An idea Melvin Conway came up with in 1968 is more relevant now than it was then. How systems are implemented over the next decade will change (I’m sure Artificial Intelligence is going to have a huge impact), but the interplay between humans and technology will remain paramount. Ideas like <em>Conway’s Law</em>, <em>The Single Responsibility Principle</em>, <em>Bounded Contexts</em>, building stream-aligned teams, and optimising for <em>flow</em> and <em>low cognitive load</em> will outlive any technology or architectural pattern.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b83d394734ce" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/designing-software-architectures-for-people-in-2023-b83d394734ce">Designing Software Architectures For People in 2023</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Beyond Test-Driven Development]]></title>
            <link>https://medium.com/cloudnative-ly/beyond-test-driven-development-f7ce3325669c?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/f7ce3325669c</guid>
            <category><![CDATA[software-testing]]></category>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[property-based-testing]]></category>
            <category><![CDATA[test-driven-development]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Sat, 12 Dec 2020 12:02:22 GMT</pubDate>
            <atom:updated>2020-12-12T12:02:22.524Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iB5mKo9MUP9sjR8oPM-RpQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@thisisengineering?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">ThisisEngineering RAEng</a> on <a href="https://unsplash.com/@thisisengineering?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I’m a firm believer that Test-Driven Development (TDD) should be the default way that software teams create code. I believe that its methodical approach leads developers to design and discover better ways to architect their software. However, I also believe that the best tool that we have today is not guaranteed to be the best tool for tomorrow. In this article, I present some of the things that I’ve explored which could perhaps replace TDD (and maybe even tests in general) as the best way to build and test software. This article does not seek to provide any answers, but rather, present some exciting things to play with.</p><blockquote>“Technologies, methodologies, and practices are constantly emerging and evolving. There is always a better way of doing things. Although we described a set of practices in this chapter, that neither means they are the only practices out there, nor that they are suitable in every single context. Things that are considered good today may not be considered as good tomorrow. Maybe in a few years time, Software Craftsmanship will be strongly encouraging the adoption of a completely different set of practices”</blockquote><blockquote><a href="https://www.amazon.co.uk/Software-Craftsman-Professionalism-Pragmatism-Robert/dp/0134052501">Software Craftsmanship</a> by Sandro Mancuso</blockquote><h3>About TDD</h3><h4>What is it?</h4><p><a href="https://en.wikipedia.org/wiki/Test-driven_development">Test-Driven Development</a> is a precise process. It is the quick iteration of the <em>red-green-refactor</em> cycle. In this cycle, we think about what we need to achieve, write a single failing test (red), write <strong>just enough</strong> code to make that test pass (green), and then refactor to improve the design. Each iteration of this cycle takes only a few minutes (or less).</p><p>There are many benefits to TDD:</p><ul><li>It gives the developer a rigorous process which makes it easy to know what to do next.</li><li>It breaks the problem down into much smaller pieces; this reduces cognitive load and allows the practitioner to maintain the state of flow.</li><li>It encourages decoupled and cohesive, modular design in your code.</li><li>It results in near 100% code coverage without even making that the focus (it should be 100%, but that’s dependant on the developers not accidentally missing a step).</li></ul><h4>What is its current state?</h4><p>The good news is that tests are much more common now than they used to be. Many projects have at least a few tests, and many developers are familiar with testing frameworks. Also, the words <em>Test-Driven Development</em> (and acronym <em>TDD</em>) feel like they are mainstream now, you can find them on many CVs and job descriptions. However, my experience tells me something a bit different about the state of TDD — having done countless interviews of people with TDD on their CV, I can count on one hand the number of people who I’ve seen do TDD by-the-book in an interview. What I see instead is people practising their own interpretation of the words “test-driven development”; this can range from processes very similar to TDD (perhaps writing a suite of tests first) to merely having some form of tests present at the end of the process.</p><p>My experience suggests that, while the term Test-Driven Development is well known, the practice still has a long way to go until it becomes mainstream. Whether TDD will ever become entirely ubiquitous for the industry or not, I do not know. However, I still think we should strive for this as a goal. TDD is, without a doubt in my mind, the most reliable way that we currently know of for writing software with the languages, tooling, processes and teams that are most common in the industry. <strong>I am, however, also a firm believer that this will not always be true!</strong></p><h4>When is TDD Appropriate?</h4><p>I think it’s also worth pointing out that TDD isn’t a tool appropriate for every single programming task; there are times when it is not the best tool for the job. Experienced TDD practitioners have explored TDD to a level where they know it’s limitations. They will know when they need to either change the process or switch processes altogether — however, this will generally be for a small part of the codebase rather than the whole project.</p><p>For general programming, TDD is usually applicable in my experience. When someone tells me that a piece of code is not able to be written using TDD, then nine times out of ten, I’ll disagree — often it requires a small change in mindset or approach. That one time I will agree though, it will be completely valid, and TDD is not the right tool.</p><p>I think it’s also worth pointing out that there are niche alternatives to TDD. These might exist in specific programming paradigms, domains or communities. These alternatives are very valid in their context; they are also some of the sources that this article draws from. However, in business software development, I stand by my statement that <strong>TDD is currently the best tool for the job</strong>.</p><p>Now we know where we are with TDD, I want to explore some different ideas…</p><h3>Evolutions of TDD</h3><p>The most obvious processes that could succeed TDD are the direct descendants of it. Many of these are TDD with some restriction applied (e.g. time limitations within the cycle) or some adjustments/additions to the process (e.g. revert changes when the tests fail).</p><p>One of the most talked-about evolutions is <a href="https://medium.com/u/a8ff3eaa42c">Kent Beck</a>’s <a href="https://medium.com/@kentbeck_7670/test-commit-revert-870bbd756864"><strong>test &amp;&amp; commit || revert</strong></a> (or TCR). With this process, every time you run the tests, the changes are committed if the tests pass, or <strong>reverted if the tests fail</strong>. A typical first reaction to trying this is that it’s infuriating, but as you proceed, you see that there are lessons to be learned.</p><p>Personally, I’m not sold on this being a better process than TDD for the experienced practitioner, but I do see it as a fantastic training tool. <em>The reason I believe that it is so valuable as a learning tool is that it forces the person using it to discover their own ways to take smaller steps — </em>this self-discovery I find much more valuable and rewarding than just following instructions from a book or teacher.</p><p>Rachel M. Carmena has created some great diagrams of some of the different flows people have developed. You can find them in the article <a href="https://rachelcarmena.github.io/2018/11/13/test-driven-programming-workflows.html">Test-driven programming workflows</a>.</p><p>While all these altered workflows are interesting, I still see them as striving towards the same goal. I thoroughly recommend experimenting with these different workflows and seeing what you learn (you definitely will learn something). Still, I see them as the evolution of TDD rather than moving beyond TDD.</p><h3>REPLs</h3><p>Many languages now come with a REPL (a “<em>read, evaluate, print loop”</em> or merely an interactive terminal). Python, Ruby and Scala, for example, all have tools which allow you to run commands and evaluate expressions interactively. The developers in communities from some languages, such as Clojure and F#, commonly use interacting with the REPL as their primary development process; that is, they iterate the development of functions by interactive tweaking and trying until they reach the desired implementation. You can call this <a href="https://www.google.com/search?q=repl+driven+development"><em>REPL-driven developmen</em></a><em>t</em>.</p><p>An evolution of REPL usage is where IDEs have implemented features where you can evaluate lines and expression inline in the code editor. When it is as convenient as hitting something like Alt+Enter to get the result of evaluating the expression on the current line, you are getting some of the fastest feedback possible.</p><p>Another variation on this, which is often found in the academic, science and data-science domains, is the use of <a href="https://jupyter.org/">Jupyter Notebooks</a> to create interactive and executable documentation. This documentation can even include things like generated graphs, tables and charts. Jupyter Notebooks combines the REPL like feedback in a <a href="https://wiki.haskell.org/Literate_programming">Literate Programming</a> context. Interactive Notebooks can provide a fantastic record of the process behind the development of the code.</p><p>The big problem I have with the use of the REPL as the primary iteration process is that you still have to write the tests. TDD gives a great way to know which tests to write, but with the REPL, you have to decide which tests to create after the fact. The caveat here is that this apparent limitation might be due to inexperience on my part.</p><h3>Types</h3><p>Let’s briefly talk about types. In languages where we can specify the types of values, we write fewer tests. For example, in Ruby we might write a test it &quot;returns an integer&quot;, but in Java, we’d define public int f(). There is no need to write such as test in Java because we trust the type system (although tests around null are still very much needed in many languages).</p><p>One thing some functional programmers like to do in strongly typed languages is to start creating a model by defining the types. Once the types are specified, then the implementations can be written, along with tests, to complete the features. You can find a great example of this in <a href="https://medium.com/u/c842d836f25b">Scott Wlaschin</a>’s fantastic <a href="https://www.amazon.co.uk/Domain-Modeling-Made-Functional-Domain-Driven/dp/1680502549">Domain Modelling Made Functional</a>, which shows a practical way to apply this approach.</p><p>Some languages have even more powerful type systems that allow for <em>type-level programming. </em>As we’re now about to see, some languages have far more advanced type systems than our mainstream languages. These languages can reduce the amount of testing required to a much greater extent.</p><h3>Proofs</h3><p>Since learning Test-Driven Development (I won’t say TDD in this section for reasons which are about to become apparent), I’ve been convinced that you must always have tests — that is until I read <a href="https://www.manning.com/books/type-driven-development-with-idris">Type-Driven Development with Idris</a>.</p><p><a href="https://www.idris-lang.org/">Idris</a> is a <em>dependently-typed language; t</em>his means that you can be much more expressive and restrictive in the type signatures of functions. This expressiveness is taken to a level at which the types of parameters and return values of functions can change and depend based on each other. This may sound complicated (it kind of is) but let’s look at a simple example. The following is a type signature for a function that joins two vectors together:</p><pre>join : (xs : Vect n elem) -&gt; (ys : Vect m elem) -&gt; Vect (n + m) elem</pre><p>This type signature states that the function join does the following:</p><ul><li>It takes one vector (Vect) as the first parameter (named xs), of any length n, and containing elements of any element type elem.</li><li>It takes another vector as the second parameter (named ys), of any length m, and containing elements of the same element type elem as in xs.</li><li>It then returns a resulting vector containing elements of the same typeelem, <strong>and it has the length of exactly</strong><strong>n + m</strong>.</li></ul><p>This example has taken one property of the algorithm to join two vectors together (i.e. “<em>the length of the resulting vector must be equal to the sum of the lengths of the two inputs</em>”) and specified that in the type. Now here’s the fun part, you don’t need to test this property of the algorithm because Idris’s compiler<strong> will not compile this code until you prove to it that this property will always hold for your implementation</strong>.</p><p>Obviously, in the example above, you still need tests as there are other properties of this algorithm that are not encoded in the type. These include:</p><ul><li><em>The resulting vector begins with the first vector</em></li><li><em>The resulting vector ends with the second vector</em></li></ul><p>It is possible with dependently typed languages to encode a lot more in the type. Some time ago, <a href="https://medium.com/u/b8efc47f5280">Johan Martinsson</a> and I paired on a FizzBuzz implementation as an Idris kata; eventually, we came up with a solution, and the types looked like this:</p><pre>IsFizz : (k : Nat) -&gt; Type<br>IsFizz k = (modNatNZ k 3 SIsNotZ = 0)</pre><pre>IsBuzz : Nat -&gt; Type<br>IsBuzz k = (modNatNZ k 5 SIsNotZ = 0)</pre><pre>data Fizzbuzz : (k: Nat) -&gt; Type where<br> Fizz : (k: Nat) -&gt; IsFizz k -&gt; Not (IsBuzz k) -&gt; Fizzbuzz k<br> Buzz : (k: Nat) -&gt; Not (IsFizz k) -&gt; IsBuzz k -&gt; Fizzbuzz k<br> FizzBuzz : (k: Nat) -&gt; IsFizz k -&gt; IsBuzz k -&gt; Fizzbuzz k<br> Normal : (k: Nat) -&gt; Not (IsFizz k) -&gt; Not (IsBuzz k) -&gt; Fizzbuzz k</pre><p>This then enabled the following implementation:</p><pre>fizzbuzz : (k: Nat) -&gt; Fizzbuzz k<br>fizzbuzz k =<br>  let isFizz = decEq (modNatNZ k 3 SIsNotZ) 0<br>      isBuzz = decEq (modNatNZ k 5 SIsNotZ) 0<br>  in case (isFizz, isBuzz) of<br>       (Yes isfizz, No notbuzz) =&gt; Fizz k isfizz notbuzz<br>       (No notfizz, Yes isbuzz) =&gt; Buzz k notfizz isbuzz<br>       (Yes isfizz, Yes isbuzz) =&gt; FizzBuzz k isfizz isbuzz<br>       (No notfizz, No notbuzz) =&gt; Normal k notfizz notbuzz</pre><p>Without going into detail of how this code works, the interesting point is that it is impossible to implement a function that does anything different than the implementation above with the type signature fizzbuzz : (k : Nat) -&gt; Fizzbuzz k. Therefore, <strong>there is no valid test that you can write for this function that would fail if the code compiled!</strong></p><p>Here I’ve shown that it’s possible (but not always practical) to write programs with Idris where tests are not needed, but Test-Driven Development is not just about the tests — it’s the methodology and process. Idris’s Type-Driven Development has its own process; it’s methodical just like Test-Driven Development, and it makes heavy use of the advanced IDE integration. Not only can Idris’s IDE integration/REPL evaluate statements, but it can also generate code and suggestions from the types. With Type-Driven Development, you specify a type and then work with the compiler to <em>define</em> and <em>refine</em> the implementation.</p><p>Dependent types and Idris’s great tooling seem near to perfection (although there are some more challenging gymnastics you have to do to convince the compiler that things are true), so why is everyone not doing it? The answer is that it’s still pretty academic, at the time I was playing with it (version 2 has since been released), it wasn’t mature enough or performant enough to write real-world applications with. It also requires some pretty radical changes in thinking from traditional software development. While there is some support for dependant and type-level programming in other languages, it’s still pretty niche and unknown — maybe this will change in the future.</p><h3>Property-Based Testing</h3><p>In the last section, I talked about properties quite a bit. We’ve seen that dependently typed languages allow us to encode properties into types, but can we test properties in languages which don’t support dependant types? This is exactly what property-based testing does.</p><p>With TDD (I’ll revert to using TDD in place of <strong>Test-</strong>Driven Development from now on), we tend to use <em>example-based tests</em>. That is, we set up the environment, then execute the test with a specific set of inputs, and finally assert that we receive a specific result. Example-based tests are ideal for TDD because they are perfectly suited to small iterations. However, a single example rarely tells us much about the system under test on its own — instead you need a suite of examples to build up a model of <em>what you think</em> the system does (one of the skills of TDD is choosing the right examples).</p><p>With a properties, we don’t state that specific inputs give a specific result, rather we state that properties hold across sets of inputs and results.</p><ul><li>“<em>when given 6 return ‘fizz’</em>” is an <strong>example</strong></li><li>“<em>when given an input divisible by 3 return a result containing ‘fizz’</em>” describes a <strong>property</strong></li></ul><p>The problem with properties is that is is too expensive, impractical or even impossible to create tests which check every possible input. Instead, property-based testing frameworks use small random samples (say 100 or 1,000 sets of inputs).</p><p>Here’s an example of how you might test the above property might using Python’s <a href="https://hypothesis.readthedocs.io/en/latest/">Hypothesis</a> framework.</p><pre>@given(x=integers())<br>def test_input_divisible_by_3_returns_fizz(x):<br>    assert f(x * 3) == &#39;fizz&#39;</pre><p>Hypothesis will run this a specific number of times (e.g.100) with random integers provided for x. This means that when you implement f you will have to provide a solution which works for any integer value of x rather than just the specific one — otherwise, the test <em>could</em> fail.</p><p>Inspecting examples allow us to estimate the behaviour of an algorithm, whereas, with properties, we can specify the complete algorithm. A set of examples for Fizz Buzz might be:</p><ul><li>1 == ‘1’</li><li>2 == ‘2’</li><li>4 == ‘4’</li><li>3 == ‘fizz’</li><li>6 == ‘fizz’</li><li>5 == ‘buzz’</li><li>6 == ‘buzz’</li><li>15 == ‘fizzbuzz’</li><li>30 == ‘fizzbuzz’</li></ul><p>From these examples, we can deduce a good guess of the behaviour of the algorithm, but having these as tests would not stop the implementation from having an overriding case saying if x &gt; 100: return &#39;flop&#39;.</p><p>A set of properties for fizzbuzz might look like this:</p><ul><li>if input is divisible by 3, return a result containing ‘fizz’</li><li>if input is divisible by 5, return a result containing ‘buzz’</li><li>if input is not divisible by 3, return a result which does not contain ‘fizz’</li><li>if input is not divisible by 5, return a result which does not contain ‘buzz’</li><li>if input is not divisible by 3 or 5, return the input</li></ul><p>Given this set of properties, there is no other implementation that holds true other than a correct one.</p><p>Property-based tests look much better than example-based tests, so why not always use them? When comparing property-based tests with example-based tests, property-based tests seem superior, but the problem with them is that the workflow is not as straightforward as when using example-based tests and TDD. For some tasks, doing TDD with property-based tests works perfectly (try the fizzbuzz example above), but for other tasks it’s not so obvious. You will often find that you end up either taking too big steps or using weak properties (rather than the ones which most characterise the algorithm) when trying to do TDD with property-based tests.</p><p>I find a combination of property-based and example-based tests works well. Sometimes it’s obvious when using a property makes sense, other times I’ll use example-based TDD and then refactor some of the example-based tests into property-based tests when I feel they are more appropriate.</p><h3>Algebra-Driven Design</h3><p>I recently discovered the book <a href="https://algebradriven.design/">Algebra-Driven Designed</a> by Sandy McGuire. What I found compelling about this approach is that it brings a methodology to using a collection of approaches (some of which I’ve mentioned already) together.</p><p>In the section about types, we talked about how some developers like to define the types as the first step when modelling in code. Sandy McGuire extends this a bit by creating the types <strong>and then determining the laws which must be true in the model </strong>(defining an algebra). In the book, Sandy builds a composable graphics library where a function called cw rotates an image tile 90 degrees clockwise. Its type signature takes a tile and returns a new tile:</p><p>cw :: Tile -&gt; Tile</p><p>An example law for this is that “<em>if you rotate the tile 4 times, then you get the original tile”</em>. He represents this like so:</p><pre>∀ (t :: Tile).<br>   cw (cw (cw (cw t))) = t</pre><p>This is very much like defining a property which we talked about earlier.</p><p>The next step with Algebra-Driven Design is to implement a minimum viable version of the algebra (known as an <em>initial encoding</em>). This encoding implements all the functions in a way that obeys all the laws but isn’t necessarily useful.</p><p>Once this reference implementation is built, a tool called <a href="https://hackage.haskell.org/package/quickspec">QuickSpec</a> is employed to <strong>discover all the properties of the model!</strong> These properties can be converted to property-based tests, and you are then free to create the implementation you desire.</p><p>The process of Algebra-Driven Development feels very different from TDD. You can define your algebra and laws with pen and paper while discovering the domain. The act of implementing is then creating the appropriate code within the laws of that algebra.</p><p>In the minimal experiments I’ve tried with Algebra-Driven Design, I’ve noticed that I tend to hit a well designed and composable API first time (as opposed to multiple refactorings before I get there). I’ve yet to be convinced that this approach can be used in all aspects required to build large systems, but it is definitely a completely different approach to that of writing code with TDD. I’m pretty sure Algebra-Driven Development excels with certain types of problem (the examples in the book are very good).</p><h3>Conclusion</h3><p>This post has been quite a journey down the rabbit hole. It doesn’t contain any answers as to what will succeed TDD, but that was never my intent. In fact, I don’t believe that anything will succeed TDD; instead, we’ll discover new and exciting methodologies that can be used as complementary tools to support each other. Each of the things I’ve mentioned has their own strengths:</p><ul><li>TDD with examples excels in simplicity, methodology and test coverage.</li><li>REPLs excel in the feedback cycle and discovery.</li><li>Property-based testing excels in clarity, extended test coverage and edge-case detection.</li><li>Type-level programming excels in correctness.</li></ul><p>I don’t know how many of the things I’ve talked about will ever become mainstream programming; they are certainly not new (many of the ideas have been around more than a decade). I think that the reason they are becoming a bit more popular now is due to the rise in popularity of functional programming (where most of these ideas have come from). In the talk <a href="https://www.youtube.com/watch?v=-dHFOjcK6pA">Polysemy: Chasing Performance in Free Monads</a>, Sandy McGuire, says that the functional programming community is generally about 30 years ahead of the mainstream community — I have no idea if this is true, but perhaps some of these ideas will become mainstream one day.</p><p>In summary, learn TDD, practice TDD and teach TDD — I think we should all be trying to make TDD more common in our work. But also don’t be dogmatic — explore crazy ideas and alternatives and see what you learn or come up with. Finally, consider reading <a href="https://www.amazon.co.uk/Domain-Modeling-Made-Functional-Domain-Driven/dp/1680502549">Domain Modelling Made Functional</a>, <a href="https://www.manning.com/books/type-driven-development-with-idris">Type-Driven Development with Idris</a> or <a href="https://leanpub.com/algebra-driven-design">Algebra-Driven Design</a> this holiday.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f7ce3325669c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/beyond-test-driven-development-f7ce3325669c">Beyond Test-Driven Development</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Refactoring — Removing Connascience of Execution Order]]></title>
            <link>https://medium.com/cloudnative-ly/refactoring-removing-connascience-of-execution-order-56b3b90bda47?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/56b3b90bda47</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[refactoring]]></category>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[software-development]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Thu, 26 Mar 2020 14:06:14 GMT</pubDate>
            <atom:updated>2020-03-26T14:06:14.563Z</atom:updated>
            <content:encoded><![CDATA[<h3>Refactoring — Removing Connascience of Execution Order</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DAr2-OiRqtZtk3n8LmxaOA.jpeg" /><figcaption>Image Source: <a href="https://pixabay.com/users/gookingsword-1861966/">GooKingSword</a> via <a href="https://pixabay.com/illustrations/dice-3d-art-blender-gambling-cubes-1542458/">Pixabay</a></figcaption></figure><p>Execution Order is the lowest strength dynamic <a href="https://cloudnative.ly/connascense-9b3972c57415">connascience</a>. The characterisation of dynamic connasciences is that they cannot be understood without considering how the code runs. When we encounter any dynamic connasciences in legacy codebases, they can present quite a challenge to understand. In this post, I present an example of how removing this type of coupling from the code can quickly help efforts to improve the understanding of the system.</p><h3>How I Got Here</h3><p>For this article, I will be using the <a href="https://github.com/jbrains/trivia">ugly trivia coding kata</a>. This is a legacy code kata where the exercise is to refactor the code to a more understandable and maintainable state.</p><p>I was first introduced to this kata about two years ago during a remote pairing session with <a href="https://twitter.com/adibolb">Adrian Bolboaca</a> (with <a href="https://www.youtube.com/watch?v=ewlVFipzoLg">part 1</a> and <a href="https://www.youtube.com/watch?v=6YZRhN7ytVc">part 2</a> posted on his <a href="https://www.youtube.com/watch?v=6YZRhN7ytVc">YouTube channel</a>). The approach we took was to create a <a href="https://codurance.com/2012/11/11/testing-legacy-code-with-golden-master/">Golden Master test </a>and then start extracting methods from the tangled code to try and gain understanding. I was never particularly pleased with the result of the pairing session as we never got to the point of truly understanding the code.</p><p>I’ve since tried the same approach that I used with Adrian several times and it’s never gone particularly well. It gives the illusion that the code is becoming understandable, but it never escapes the fact that there’s a strange coupling between methods which is very hard to reason about.</p><p>At DDD Europe 2020 I took part in <a href="https://medium.com/u/b8efc47f5280">Johan Martinsson</a>’s Bug Zero Kata workshop. Johan uses the same kata as the basis of this workshop. This time I took a very different approach with my pair. Rather than starting by trying to make the code more descriptive, we removed the source of the confusion early on — this source of confusion was the <em>connascience of execution order</em>.</p><p>At first, this step seemed to make the code messier (creating one big method), but the result was that all the tangled code was brought together into one place and the connascience of execution order was removed. From this point on, refactoring was easy.</p><p>Now I’ll show this in action.</p><h3>The Initial Code</h3><p>You can get the original, legacy <a href="https://github.com/jbrains/trivia">Ugly Trivia code from GitHub</a>. It comes in many different languages; I have chosen Java for this article. The code comprises of two classes, the Game class and the GameRunner class.</p><p>Below you can see some of the Game class, there’s more in it than what I have shown below, but this is the part we’re interested in. Please don’t try and understand the detail of this code, rather, notice that the methods roll(), wasAnsweredCorrectly() and wrongAnswer() are three different public methods that depend on the states of inPenaltyBox and isGettingOutOfPenaltyBox. Without knowing which order these are called in (or even when you do know) it’s very hard to understand what this code is doing.</p><pre>public class Game {<br><em>    /* More fields are defined here */</em><br><br>    boolean[] inPenaltyBox  = new boolean[6];<br><br>    int currentPlayer = 0;<br>    boolean isGettingOutOfPenaltyBox;<br><br>    public void roll(int roll) {<br>        System.<em>out</em>.println(players.get(currentPlayer) +<br>            &quot; is the current player&quot;);<br>        System.<em>out</em>.println(&quot;They have rolled a &quot; + roll);<br><br>        if (<strong>inPenaltyBox</strong>[currentPlayer]) {<br>            if (roll % 2 != 0) {<br>                <strong>isGettingOutOfPenaltyBox</strong> = true;<br><br>                System.<em>out</em>.println(players.get(currentPlayer) +<br>                    &quot; is getting out of the penalty box&quot;);<br>                places[currentPlayer] = places[currentPlayer] +<br>                    roll;<br>                if (places[currentPlayer] &gt; 11)<br>                    places[currentPlayer] =<br>                        places[currentPlayer] - 12;<br><br>                System.<em>out</em>.println(players.get(currentPlayer)<br>                        + &quot;&#39;s new location is &quot;<br>                        + places[currentPlayer]);<br>                System.<em>out</em>.println(&quot;The category is &quot; +<br>                    currentCategory());<br>                askQuestion();<br>            } else {<br>                System.<em>out</em>.println(players.get(currentPlayer) +<br>                    &quot; is not getting out of the penalty box&quot;);<br>                <strong>isGettingOutOfPenaltyBox</strong> = false;<br>            }<br>        } else {<br>            places[currentPlayer] = places[currentPlayer] + roll;<br>            if (places[currentPlayer] &gt; 11)<br>                places[currentPlayer] = places[currentPlayer] - 12;<br><br>            System.<em>out</em>.println(players.get(currentPlayer)<br>                    + &quot;&#39;s new location is &quot;<br>                    + places[currentPlayer]);<br>            System.<em>out</em>.println(&quot;The category is &quot; +<br>                currentCategory());<br>            askQuestion();<br>        }<br>    }<br><br>    public boolean wasCorrectlyAnswered() {<br>        if (<strong>inPenaltyBox</strong>[currentPlayer]){<br>            if (<strong>isGettingOutOfPenaltyBox</strong>) {<br>                System.<em>out</em>.println(&quot;Answer was correct!!!!&quot;);<br>                purses[currentPlayer]++;<br>                System.<em>out</em>.println(players.get(currentPlayer)<br>                        + &quot; now has &quot;<br>                        + purses[currentPlayer]<br>                        + &quot; Gold Coins.&quot;);<br><br>                boolean winner = didPlayerWin();<br>                currentPlayer++;<br>                if (currentPlayer == players.size())<br>                    currentPlayer = 0;<br><br>                return winner;<br>            } else {<br>                currentPlayer++;<br>                if (currentPlayer == players.size())<br>                    currentPlayer = 0;<br>                return true;<br>            }<br>        } else {<br>            System.<em>out</em>.println(&quot;Answer was corrent!!!!&quot;);<br>            purses[currentPlayer]++;<br>            System.<em>out</em>.println(players.get(currentPlayer)<br>                    + &quot; now has &quot;<br>                    + purses[currentPlayer]<br>                    + &quot; Gold Coins.&quot;);<br><br>            boolean winner = didPlayerWin();<br>            currentPlayer++;<br>            if (currentPlayer == players.size()) currentPlayer = 0;<br><br>            return winner;<br>        }<br>    }<br><br>    public boolean wrongAnswer(){<br>        System.<em>out</em>.println(&quot;Question was incorrectly answered&quot;);<br>        System.<em>out</em>.println(players.get(currentPlayer) +<br>            &quot; was sent to the penalty box&quot;);<br>        <strong>inPenaltyBox</strong>[currentPlayer] = true;<br><br>        currentPlayer++;<br>        if (currentPlayer == players.size()) currentPlayer = 0;<br>        return true;<br>    }<br><br>    <em>/* More methods are defined here */</em><br>}</pre><p>In the GameRunner class, we get to see how these methods are called. The two classes are coupled, such that the order in which the methods are called in GameRunner is critical to the behaviour inside the methods in Game. This is the connascience of execution order.</p><pre>public class GameRunner {<br><br>    private static boolean <em>notAWinner</em>;<br><br>    public static void main(String[] args) {<br>        Game aGame = new Game();<br><br>        aGame.add(&quot;Chet&quot;);<br>        aGame.add(&quot;Pat&quot;);<br>        aGame.add(&quot;Sue&quot;);<br><br>        Random rand = new Random();<br><br>        do {<br>            <strong>aGame.roll(rand.nextInt(5) + 1);</strong><br><br>            if (rand.nextInt(9) == 7) {<br>                <em>notAWinner </em>= <strong>aGame.wrongAnswer();</strong><br>            } else {<br>                <em>notAWinner </em>= <strong>aGame.wasCorrectlyAnswered();</strong><br>            }<br>        } while (<em>notAWinner</em>);<br>    }<br>}</pre><p>This connascience of execution order is what makes the code in Game hard to understand.</p><h3>Adding Tests</h3><p>Before we make any changes, we need to add tests to give us the confidence that we don’t break anything. For legacy code like this, creating a <a href="https://codurance.com/2012/11/11/testing-legacy-code-with-golden-master/">golden master</a> is a good approach. I’m not going to explain how to do this here, but you can find details in one of the following ways:</p><ul><li>Read <a href="https://codurance.com/2012/11/11/testing-legacy-code-with-golden-master/">Sandro’s post</a> on golden master testing with the Approvals testing framework.</li><li>Review the test from the <a href="https://github.com/martinsson/BugsZero-Kata/blob/master/java/src/test/java/com/adaptionsoft/games/trivia/GameTest.java">Bug Zero kata codebase</a> which uses the <a href="https://approvaltests.com/">Approvals testing framework</a>.</li><li>Review the <a href="https://www.youtube.com/watch?v=ewlVFipzoLg">first video</a> of the session I recorded with Adrian.</li></ul><p>Since the GameRunner uses Random to generate its behaviour, we need to seed it to have a consistent test. To make this possible, I used IntelliJ’s Extract Method refactoring to separate the creation of the Random object from the rest of the code like so:</p><pre>public class GameRunner {<br>    private static boolean <em>notAWinner</em>;<br><br>    public static void main(String[] args) {<br>        <em>run</em>(new Random());<br>    }<br><br>    public static void run(Random rand) {<br>        Game aGame = new Game();<br><br>        aGame.add(&quot;Chet&quot;);<br>        aGame.add(&quot;Pat&quot;);<br>        aGame.add(&quot;Sue&quot;);<br><br>        do {<br>            aGame.roll(rand.nextInt(5) + 1);<br><br>            if (rand.nextInt(9) == 7) {<br>                <em>notAWinner </em>= aGame.wrongAnswer();<br>            } else {<br>                <em>notAWinner </em>= aGame.wasCorrectlyAnswered();<br>            }<br>        } while (<em>notAWinner</em>);<br>    }<br>}</pre><p>This allows the golden master test to create its own instance of Random and call the run() method with it, while still keeping the main() function behaving as it always has. <em>Note, this is a temporary step and not something I’d leave in the codebase permanently.</em></p><p>For completeness, my test looks like this.</p><pre>public class GameTest {<br>    @Test<br>    public void golden_master() {<br>        Approvals.<em>verify</em>(runWithStdout());<br>    }<br><br>    private String runWithStdout() {<br>        ByteArrayOutputStream baos = new ByteArrayOutputStream();<br>        PrintStream ps = new PrintStream(baos);<br>        PrintStream old = System.<em>out</em>;<br>        System.<em>setOut</em>(ps);<br><br>        for (int seed = 1; seed &lt; 20; seed++) {<br>            Random random = new Random(seed);<br>            GameRunner.<em>runMain</em>(random);<br>        }<br><br>        System.<em>out</em>.flush();<br>        System.<em>setOut</em>(old);<br>        return baos.toString();<br>    }<br>}</pre><p>Here you should use <em>code coverage reports</em> and <em>mutation testing</em> (see <a href="https://medium.com/u/58c48d3546e">Billie Thompson</a>’s video <a href="https://cloudnative.ly/mutation-testing-f9e415046bb7">here</a> if you don’t know what mutation testing is) to gain some confidence about how much you can rely on this test — finding ways to increase the confidence if it’s not good enough. I’m not going to go into any more detail on that now but it may be something I write more about in the future.</p><h3>Removing Execution Order Connascience</h3><p>Now we have a golden master test, we can confidently start refactoring. The first thing I want to try and do is remove the connascience of execution order. For this, I’m going to focus on the three methods being called inside the loop. Technically the calls to add() also form connascience of execution order, but they aren’t causing too much confusion right now, so I’ll leave that until later.</p><p>To remove connascience of execution order from the loop, I want GameRunner to make just one call to Game in each iteration of the loop. The first step I take is to separate the inputs from the logic inside of the loop in the run() method. Here the random numbers are the <em>inputs</em>, so I use the Extract Variable refactoring each time a random number is generated and move the declarations to the top of the loop (the important thing is to ensure the order of generating the numbers doesn’t change).</p><pre>public static void run(Random rand) {<br>   Game aGame = new Game();<br><br>   aGame.add(&quot;Chet&quot;);<br>   aGame.add(&quot;Pat&quot;);<br>   aGame.add(&quot;Sue&quot;);<br><br>   do {<br><strong>      int roll = rand.nextInt(5) + 1;<br>      boolean incorrectAnswer = rand.nextInt(9) == 7;</strong><br>      <br>      aGame.roll(<strong>roll</strong>);<br><br>      if (<strong>incorrectAnswer</strong>) {<br>         <em>notAWinner </em>= aGame.wrongAnswer();<br>      } else {<br>         <em>notAWinner </em>= aGame.wasCorrectlyAnswered();<br>      }<br>   } while (<em>notAWinner</em>);<br>}</pre><p>I also notice that notAWinner is defined as a static field on the class, but it is only ever used in local scope, so I make it a local variable.</p><pre>public static void run(Random rand) {<br>   Game aGame = new Game();<br><br>   aGame.add(&quot;Chet&quot;);<br>   aGame.add(&quot;Pat&quot;);<br>   aGame.add(&quot;Sue&quot;);<br><br>   <strong>boolean notAWinner;</strong><br>   <br>   do {<br>      int roll = rand.nextInt(5) + 1;<br>      boolean incorrectAnswer = rand.nextInt(9) == 7;<br><br>      aGame.roll(roll);<br><br>      if (incorrectAnswer) {<br>         notAWinner = aGame.wrongAnswer();<br>      } else {<br>         notAWinner = aGame.wasCorrectlyAnswered();<br>      }<br>   } while (notAWinner);<br>}</pre><p>I now use Extract Method to move the logic to a new playTurn() method.</p><pre>private static void run(Random rand) {<br>   Game aGame = new Game();<br><br>   aGame.add(&quot;Chet&quot;);<br>   aGame.add(&quot;Pat&quot;);<br>   aGame.add(&quot;Sue&quot;);<br><br>   boolean notAWinner;<br><br>   do {<br>      int roll = rand.nextInt(5) + 1;<br>      boolean incorrectAnswer = rand.nextInt(9) == 7;<br><br>      notAWinner = <strong><em>playTurn</em>(aGame, roll, incorrectAnswer)</strong>;<br>   } while (notAWinner);<br>}<br><br><strong>private static boolean playTurn(<br>        Game aGame, int roll, boolean incorrectAnswer) {<br>   boolean notAWinner;<br>   aGame.roll(roll);<br><br>   if (incorrectAnswer) {<br>      notAWinner = aGame.wrongAnswer();<br>   } else {<br>      notAWinner = aGame.wasCorrectlyAnswered();<br>   }<br>   return notAWinner;<br>}</strong></pre><p>Finally, I can use IntelliJ’s Convert To Instance Method refactoring on playTurn() to move it into theGame class.</p><p><strong>GameRunner:</strong></p><pre>public class GameRunner {<br>   public static void main(String[] args) {<br>      <em>run</em>(new Random());<br>   }<br><br>   private static void run(Random rand) {<br>      Game aGame = new Game();<br><br>      aGame.add(&quot;Chet&quot;);<br>      aGame.add(&quot;Pat&quot;);<br>      aGame.add(&quot;Sue&quot;);<br><br>      boolean notAWinner;<br><br>      do {<br>         int roll = rand.nextInt(5) + 1;<br>         boolean incorrectAnswer = rand.nextInt(9) == 7;<br><br>         notAWinner = <strong>aGame.playTurn(roll, incorrectAnswer);</strong><br>      } while (notAWinner);<br>   }<br>}</pre><p><strong>Game:</strong></p><pre>public class Game {<br>    /* Other class content */</pre><pre><strong>    public boolean playTurn(int roll, boolean incorrectAnswer) {<br>        boolean notAWinner;<br>        roll(roll);<br><br>        if (incorrectAnswer) {<br>            notAWinner = wrongAnswer();<br>        } else {<br>            notAWinner = wasCorrectlyAnswered();<br>        }<br>        return notAWinner;<br>    }</strong><br>}</pre><p>At this point, I have removed the connascience of execution order from the loop. But what has this achieved?</p><p>We still have all this complicated logic spread throughout the methods in Game, but now all the calls to these methods is from the same class (in the language of connascience, the coupling is more local). One benefit here is that the Game and GameRunner classes are less coupled, but we’ve only made a minor impact on the clarity of the code. Let’s see what can be done now.</p><h3>Inlining the Methods</h3><p>Because all these methods are now in the same class, I can inline them all into playTurn() and see if it presents any new ways to structure the code. Specifically, in this case, we can use the approach I described in <a href="https://medium.com/p/cc5693b8ec3c/edit?source=your_stories_page---------------------------">Refactoring — Untangling Conditionals</a> to localise the complexity and quickly refactor the logic to a more desirable state.</p><p>The inlining looks like this:</p><pre>public boolean playTurn(int roll, boolean incorrectAnswer) {<br>    boolean notAWinner;<br>    System.<em>out</em>.println(players.get(currentPlayer) +<br>        &quot; is the current player&quot;);<br>    System.<em>out</em>.println(&quot;They have rolled a &quot; + roll);<br><br>    if (inPenaltyBox[currentPlayer]) {<br>        if (roll % 2 != 0) {<br>            isGettingOutOfPenaltyBox = true;<br><br>            System.<em>out</em>.println(players.get(currentPlayer) +<br>                &quot; is getting out of the penalty box&quot;);<br>            places[currentPlayer] =<br>                places[currentPlayer] + roll;<br>            if (places[currentPlayer] &gt; 11)<br>                places[currentPlayer] = places[currentPlayer] - 12;<br><br>            System.<em>out</em>.println(players.get(currentPlayer)<br>                    + &quot;&#39;s new location is &quot;<br>                    + places[currentPlayer]);<br>            System.<em>out</em>.println(&quot;The category is &quot; + <br>                currentCategory());<br>            askQuestion();<br>        } else {<br>            System.<em>out</em>.println(players.get(currentPlayer) +<br>                &quot; is not getting out of the penalty box&quot;);<br>            isGettingOutOfPenaltyBox = false;<br>        }<br>    } else {<br>        places[currentPlayer] = places[currentPlayer] + roll;<br>        if (places[currentPlayer] &gt; 11)<br>            places[currentPlayer] = places[currentPlayer] - 12;<br><br>        System.<em>out</em>.println(players.get(currentPlayer)<br>                + &quot;&#39;s new location is &quot;<br>                + places[currentPlayer]);<br>        System.<em>out</em>.println(&quot;The category is &quot; + currentCategory());<br>        askQuestion();<br>    }<br><br>    if (incorrectAnswer) {<br>        System.<em>out</em>.println(&quot;Question was incorrectly answered&quot;);<br>        System.<em>out</em>.println(players.get(currentPlayer) +<br>            &quot; was sent to the penalty box&quot;);<br>        inPenaltyBox[currentPlayer] = true;<br><br>        currentPlayer++;<br>        if (currentPlayer == players.size()) currentPlayer = 0;<br>        notAWinner = true;<br>    } else {<br>        boolean result;<br>        if (inPenaltyBox[currentPlayer]) {<br>            if (isGettingOutOfPenaltyBox) {<br>                System.<em>out</em>.println(&quot;Answer was correct!!!!&quot;);<br>                purses[currentPlayer]++;<br>                System.<em>out</em>.println(players.get(currentPlayer)<br>                        + &quot; now has &quot;<br>                        + purses[currentPlayer]<br>                        + &quot; Gold Coins.&quot;);<br><br>                boolean winner = didPlayerWin();<br>                currentPlayer++;<br>                if (currentPlayer == players.size())<br>                    currentPlayer = 0;<br><br>                result = winner;<br>            } else {<br>                currentPlayer++;<br>                if (currentPlayer == players.size())<br>                    currentPlayer = 0;<br>                result = true;<br>            }<br>        } else {<br>            System.<em>out</em>.println(&quot;Answer was corrent!!!!&quot;);<br>            purses[currentPlayer]++;<br>            System.<em>out</em>.println(players.get(currentPlayer)<br>                    + &quot; now has &quot;<br>                    + purses[currentPlayer]<br>                    + &quot; Gold Coins.&quot;);<br><br>            boolean winner = didPlayerWin();<br>            currentPlayer++;<br>            if (currentPlayer == players.size()) currentPlayer = 0;<br><br>            result = winner;<br>        }<br>        notAWinner = result;<br>    }<br>    return notAWinner;<br>}</pre><p>This is a pretty horrible piece of code, but by applying the techniques from <a href="https://medium.com/p/cc5693b8ec3c/edit?source=your_stories_page---------------------------">Refactoring — Untangling Conditionals</a>, I’m able to start simplifying the code. This brings me to something like this:</p><pre>public boolean playTurn(int roll, boolean incorrectAnswer) {<br>    System.<em>out</em>.println(players.get(currentPlayer) +<br>        &quot; is the current player&quot;);<br>    System.<em>out</em>.println(&quot;They have rolled a &quot; + roll);</pre><pre>    boolean notAWinner;<br>    notAWinner = moveAndAnswerQuestion(roll, incorrectAnswer);<br>    nextPlayer();<br>    return notAWinner;<br>}<br><br>private boolean moveAndAnswerQuestion(int roll,<br>                                      boolean incorrectAnswer) {<br>    if (inPenaltyBox[currentPlayer]) {<br>        if (failedToLeavePenaltyBox(roll, incorrectAnswer)) {<br>            return true;<br>        }<br>    }<br><br>    move(roll);<br>    askQuestion();<br><br>    if (incorrectAnswer) {<br>        answerIncorrectly();<br>        return true;<br>    }<br><br>    answerCorrectly();<br>    return didPlayerWin();<br>}<br><br>private boolean failedToLeavePenaltyBox(int roll,<br>                                        boolean incorrectAnswer) {<br>    boolean rollIsOdd = roll % 2 != 0;<br><br>    if (rollIsOdd) {<br>        System.<em>out</em>.println(players.get(currentPlayer) +<br>            &quot; is getting out of the penalty box&quot;);<br>        return false;<br>    }<br><br>    System.<em>out</em>.println(players.get(currentPlayer) +<br>        &quot; is not getting out of the penalty box&quot;);<br><br>    if (incorrectAnswer) {<br>        answerIncorrectly();<br>        return true;<br>    }<br><br>    return true;<br>}<br><br>private void answerCorrectly() {<br>    System.<em>out</em>.println(&quot;Answer was correct!!!!&quot;);<br>    purses[currentPlayer]++;<br>    System.<em>out</em>.println(players.get(currentPlayer)<br>        + &quot; now has &quot;<br>        + purses[currentPlayer]<br>        + &quot; Gold Coins.&quot;);<br>}<br><br>private void answerIncorrectly() {<br>    System.<em>out</em>.println(&quot;Question was incorrectly answered&quot;);<br>    System.<em>out</em>.println(players.get(currentPlayer) +<br>        &quot; was sent to the penalty box&quot;);<br>    inPenaltyBox[currentPlayer] = true;<br>}<br><br>private void move(int roll) {<br>    places[currentPlayer] = places[currentPlayer] + roll;<br>    if (places[currentPlayer] &gt; 11)<br>        places[currentPlayer] = places[currentPlayer] - 12;<br><br>    System.<em>out</em>.println(players.get(currentPlayer)<br>        + &quot;&#39;s new location is &quot;<br>        + places[currentPlayer]);<br>    System.<em>out</em>.println(&quot;The category is &quot; + currentCategory());<br>}<br><br>private void nextPlayer() {<br>    currentPlayer++;<br>    if (currentPlayer == players.size()) currentPlayer = 0;<br>}</pre><p>This last step took about 30 minutes of moving the structure of the code about and then extracting methods. The process was not mentally taxing and it didn’t require me to understand the code. It was just a process of repeatedly adjusting (improving) the structure and checking that the tests still passed.</p><p>During the process, I identified one typo bug and fixed that, and I completely removed the isGettingOutOfPenaltyBox field from the class. The result is not beautiful code, but it is rationalised enough that I can now start to understand the logic enough to make some more interesting architectural decisions (perhaps extracting out Roll and Player classes for example). I even started to understand enough to start questioning the logic and whether there might be a bug.</p><h3>Conclusion</h3><p>To refactor legacy code, we don’t necessarily need to understand the logic we are refactoring first, rather, we can use the process of refactoring to gain understanding. However, <strong>to do this we need tests that we trust! </strong>We can use techniques like <em>golden master tests</em> to when we don’t already have tests, and we can use code coverage and mutation testing to start to gain confidence in these tests. <em>Note that the purpose of such a test is not to test the system behaviour is correct, but rather to test that we do not change the behaviour while we refactor.</em></p><p>Once we are ready to start refactoring, we might be tempted to start applying techniques which will make the code “more readable”. However, some times there is some complexity which gets in the way of this. Identifying and removing that first can be a more productive approach. In this case, the complexity came from the connascience of execution order. If you identify any of the dynamic types of connascience in your code then it’s a good indicator that it might be a candidate for something to try and remove first.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=56b3b90bda47" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/refactoring-removing-connascience-of-execution-order-56b3b90bda47">Refactoring — Removing Connascience of Execution Order</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Refactoring — Untangling Conditionals]]></title>
            <link>https://medium.com/cloudnative-ly/refactoring-untangling-conditionals-cc5693b8ec3c?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/cc5693b8ec3c</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[refactoring]]></category>
            <category><![CDATA[articles]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Thu, 19 Mar 2020 19:07:06 GMT</pubDate>
            <atom:updated>2020-03-19T19:07:06.565Z</atom:updated>
            <content:encoded><![CDATA[<h3>Refactoring — Untangling Conditionals</h3><p>As programmers, we love to minimise duplication and maximise reuse. We love the acronym DRY —<em> Don’t Repeat Yourself,</em> we hate deeply nested blocks of code, and we like small short methods and functions. However, sometimes duplicating code and embedding blocks inside other blocks can be the perfect enabler for refactoring. This is what I will demonstrate in this article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*cJRahnoHH22G7LJ_yqTsdA.jpeg" /><figcaption>Image Source: <a href="https://pixabay.com/users/_alicja_-5975425/">_Alicja_</a> via <a href="https://pixabay.com/photos/wool-yarn-color-tangled-handicraft-3820129/">Pixabay</a></figcaption></figure><p><em>Just to be clear, what I’m talking about are steps along the way in your refactoring journey. I’m not suggesting that you should leave long methods full of duplication and nested </em><em>if statements in your code, rather, these are small steps you can take along the way. I previously recorded some videos about taking small steps when refactoring </em><a href="https://cloudnative.ly/parallel-change-refactoring-f5f3c9188a90"><em>here</em></a><em> and </em><a href="https://cloudnative.ly/composing-refactorings-989f93f4a7a2"><em>here</em></a><em>, you may want to watch them first.</em></p><h3>The Starting Code</h3><p>I’ve created a small refactoring kata for this article (the repository is available <a href="https://github.com/tomphp/untangled-conditionals-kata">here</a> if you want to try it yourself). It starts with the following code. The goal is to untangle it into something easier to understand.</p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean buildSuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br>    }<br><br>    if (testsPassed) {<br>        if (&quot;success&quot;.equals(project.build())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            buildSuccessful = true;<br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            buildSuccessful = false;<br>        }<br>    } else {<br>        buildSuccessful = false;<br>    }<br><br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        if (testsPassed) {<br>            if (buildSuccessful) {<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                emailer.send(&quot;Deployment failed&quot;);<br>            }<br>        } else {<br>            emailer.send(&quot;Tests failed&quot;);<br>        }<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</pre><p>The sign that the refactoring approach that I’m about to demonstrate is appropriate in this code is that there are values that are being set, checked, updated, and rechecked through multiple if statements. That is, there are multiple top-level if blocks that a coupled by local, mutable state.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yU4gwSuRompdIWm50TmBFQ.png" /></figure><p>All these embedded if statements make this code hard to follow. Maybe we can find a way to simplify this code by bringing the sets and checks closer together, let’s try it.</p><h3>Adding Duplication</h3><p>My initial goal here is to bring the checks of testsPassed and buildSuccessful closer to where they have their values set — maybe then we can even remove the mutable state altogether.</p><p>I’m going to start by moving the second top-level if block into <strong>both</strong> of the branches of the first top-level if block.</p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean deploySuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br>        }<br><br><strong>        if (testsPassed) {<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>            }<br>        } else {<br>            deploySuccessful = false;<br>        }</strong><br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br>        <br><strong>        if (testsPassed) {<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>            }<br>        } else {<br>            deploySuccessful = false;<br>        }</strong><br>    }<br><br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        if (testsPassed) {<br>            if (deploySuccessful) {<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                emailer.send(&quot;Deployment failed&quot;);<br>            }<br>        } else {<br>            emailer.send(&quot;Tests failed&quot;);<br>        }<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</pre><p>In fact, I’m going to do the same thing again with the inner if statements in the first branch.</p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean deploySuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br><strong>            if (testsPassed) {<br>                if (&quot;success&quot;.equals(project.deploy())) {<br>                    log.info(&quot;Deployment successful&quot;);<br>                    deploySuccessful = true;<br>                } else {<br>                    log.severe(&quot;Deployment failed&quot;);<br>                    deploySuccessful = false;<br>                }<br>            } else {<br>                deploySuccessful = false;<br>            }</strong><br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br><strong>            if (testsPassed) {<br>                if (&quot;success&quot;.equals(project.deploy())) {<br>                    log.info(&quot;Deployment successful&quot;);<br>                    deploySuccessful = true;<br>                } else {<br>                    log.severe(&quot;Deployment failed&quot;);<br>                    deploySuccessful = false;<br>                }<br>            } else {<br>                deploySuccessful = false;<br>            }</strong><br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br><br>        if (testsPassed) {<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>            }<br>        } else {<br>            deploySuccessful = false;<br>        }<br>    }<br><br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        if (testsPassed) {<br>            if (deploySuccessful) {<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                emailer.send(&quot;Deployment failed&quot;);<br>            }<br>        } else {<br>            emailer.send(&quot;Tests failed&quot;);<br>        }<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</pre><p>The tests still pass but this definitely doesn’t feel like an improvement right?</p><p>However, now we have some of the if statements right after where testsPassed is being set. This makes some of these inner branches impossible to be reached, so let’s remove those.</p><p><em>Note, IntelliJ will help you locate and remove unreachable branches.</em></p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean deploySuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>            }<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br>            deploySuccessful = false;<br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br><br>        if (&quot;success&quot;.equals(project.deploy())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            deploySuccessful = true;<br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            deploySuccessful = false;<br>        }<br>    }<br><br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        if (testsPassed) {<br>            if (deploySuccessful) {<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                emailer.send(&quot;Deployment failed&quot;);<br>            }<br>        } else {<br>            emailer.send(&quot;Tests failed&quot;);<br>        }<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</pre><p>That’s improved things a bit, but we are still left with some duplication. Before we address that, let’s repeat the process we just went through, this time for the bottom top-level if statement.</p><p>First duplicate:</p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean deploySuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>                <strong>if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    if (testsPassed) {<br>                        if (deploySuccessful) {<br>                            emailer.send(&quot;Deployment completed successfully&quot;);<br>                        } else {<br>                            emailer.send(&quot;Deployment failed&quot;);<br>                        }<br>                    } else {<br>                        emailer.send(&quot;Tests failed&quot;);<br>                    }<br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }</strong><br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>                <strong>if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    if (testsPassed) {<br>                        if (deploySuccessful) {<br>                            emailer.send(&quot;Deployment completed successfully&quot;);<br>                        } else {<br>                            emailer.send(&quot;Deployment failed&quot;);<br>                        }<br>                    } else {<br>                        emailer.send(&quot;Tests failed&quot;);<br>                    }</strong><br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }<br>            }<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br>            deploySuccessful = false;<br>           <strong> if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                if (testsPassed) {<br>                    if (deploySuccessful) {<br>                        emailer.send(&quot;Deployment completed successfully&quot;);<br>                    } else {<br>                        emailer.send(&quot;Deployment failed&quot;);<br>                    }<br>                } else {<br>                    emailer.send(&quot;Tests failed&quot;);<br>                }<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }</strong><br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br><br>        if (&quot;success&quot;.equals(project.deploy())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            deploySuccessful = true;<br>            <strong>if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                if (testsPassed) {<br>                    if (deploySuccessful) {<br>                        emailer.send(&quot;Deployment completed successfully&quot;);<br>                    } else {<br>                        emailer.send(&quot;Deployment failed&quot;);<br>                    }<br>                } else {<br>                    emailer.send(&quot;Tests failed&quot;);<br>                }<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }</strong><br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            deploySuccessful = false;<br>            <strong>if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                if (testsPassed) {<br>                    if (deploySuccessful) {<br>                        emailer.send(&quot;Deployment completed successfully&quot;);<br>                    } else {<br>                        emailer.send(&quot;Deployment failed&quot;);<br>                    }<br>                } else {<br>                    emailer.send(&quot;Tests failed&quot;);<br>                }<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }</strong><br>        }<br>    }<br>}</pre><p>Then remove all unreachable branches:</p><pre>public void run(Project project) {<br>    boolean testsPassed;<br>    boolean deploySuccessful;<br><br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            testsPassed = true;<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                deploySuccessful = true;<br>                if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    emailer.send(&quot;Deployment completed successfully&quot;);<br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                deploySuccessful = false;<br>                if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    emailer.send(&quot;Deployment failed&quot;);<br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }<br>            }<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            testsPassed = false;<br>            deploySuccessful = false;<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Tests failed&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>        testsPassed = true;<br><br>        if (&quot;success&quot;.equals(project.deploy())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            deploySuccessful = true;<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            deploySuccessful = false;<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Deployment failed&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        }<br>    }<br>}</pre><p>Now we see that the intermediate variables are no longer used, let’s remove them too:</p><pre>public void run(Project project) {<br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    emailer.send(&quot;Deployment completed successfully&quot;);<br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }<br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                if (config.sendEmailSummary()) {<br>                    log.info(&quot;Sending email&quot;);<br>                    emailer.send(&quot;Deployment failed&quot;);<br>                } else {<br>                    log.info(&quot;Email disabled&quot;);<br>                }<br>            }<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Tests failed&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br><br>        if (&quot;success&quot;.equals(project.deploy())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Deployment completed successfully&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            if (config.sendEmailSummary()) {<br>                log.info(&quot;Sending email&quot;);<br>                emailer.send(&quot;Deployment failed&quot;);<br>            } else {<br>                log.info(&quot;Email disabled&quot;);<br>            }<br>        }<br>    }<br>}</pre><p>We are left with a single, large, multi-level conditional block. This block contains quite a lot of duplication, so now let’s change our focus to addressing that.</p><h3>Removing Duplication</h3><p>The most obviously repeated blocks are the if (config.sendEmailSummary()) ones. Let’s use extract method to remove this duplication.</p><pre>public void run(Project project) {<br>    if (project.hasTests()) {<br>        if (&quot;success&quot;.equals(project.runTests())) {<br>            log.info(&quot;Tests passed&quot;);<br>            if (&quot;success&quot;.equals(project.deploy())) {<br>                log.info(&quot;Deployment successful&quot;);<br>                <strong>sendEmail(&quot;Deployment completed successfully&quot;);</strong><br>            } else {<br>                log.severe(&quot;Deployment failed&quot;);<br>                <strong>sendEmail(&quot;Deployment failed&quot;);</strong><br>            }<br>        } else {<br>            log.severe(&quot;Tests failed&quot;);<br>            <strong>sendEmail(&quot;Tests failed&quot;);</strong><br>        }<br>    } else {<br>        log.info(&quot;No tests&quot;);<br><br>        if (&quot;success&quot;.equals(project.deploy())) {<br>            log.info(&quot;Deployment successful&quot;);<br>            <strong>sendEmail(&quot;Deployment completed successfully&quot;);</strong><br>        } else {<br>            log.severe(&quot;Deployment failed&quot;);<br>            <strong>sendEmail(&quot;Deployment failed&quot;);</strong><br>        }<br>    }<br>}<br><br><strong>private void sendEmail(String message) {<br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        emailer.send(message);<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</strong></pre><p>Now things are starting to look better!</p><p>Next, we can use the Invert &#39;if&#39; condition and <em>convert conditional to guard clause</em> refactorings to make it possible to remove the other duplicated block.</p><pre>public void run(Project project) {<br>    if (project.hasTests()) {<br>        if (!&quot;success&quot;.equals(project.runTests())) {<br>            log.severe(&quot;Tests failed&quot;);<br>            sendEmail(&quot;Tests failed&quot;);<br>            <strong>return;</strong><br>        }<br>        log.info(&quot;Tests passed&quot;);<br>    } else {<br>        log.info(&quot;No tests&quot;);<br>    }<br><br><strong>    if (&quot;success&quot;.equals(project.deploy())) {<br>        log.info(&quot;Deployment successful&quot;);<br>        sendEmail(&quot;Deployment completed successfully&quot;);<br>    } else {<br>        log.severe(&quot;Deployment failed&quot;);<br>        sendEmail(&quot;Deployment failed&quot;);<br>    }</strong><br>}<br><br>private void sendEmail(String message) {<br>    if (config.sendEmailSummary()) {<br>        log.info(&quot;Sending email&quot;);<br>        emailer.send(message);<br>    } else {<br>        log.info(&quot;Email disabled&quot;);<br>    }<br>}</pre><p>Finally, we can use all the basic refactoring techniques to <em>extract methods</em> and <em>remove else statements. </em>With a bit of work we can refactor the code to something much more understandable and manageable:</p><pre>public void run(Project project) {<br>    if (testsFailed(project)) {<br>        sendEmail(&quot;Tests failed&quot;);<br>        return;<br>    }<br><br>    if (deployFailed(project)) {<br>        sendEmail(&quot;Deployment failed&quot;);<br>        return;<br>    }<br><br>    sendEmail(&quot;Deployment completed successfully&quot;);<br>}<br><br>private boolean testsFailed(Project project) {<br>    if (!project.hasTests()) {<br>        log.info(&quot;No tests&quot;);<br>        return false;<br>    }<br><br>    if (&quot;success&quot;.equals(project.runTests())) {<br>        log.info(&quot;Tests passed&quot;);<br>        return false;<br>    }<br><br>    log.severe(&quot;Tests failed&quot;);<br>    return true;<br>}<br><br>private boolean deployFailed(Project project) {<br>    boolean deployFailed = !&quot;success&quot;.equals(project.deploy());<br>    if (deployFailed) {<br>        log.severe(&quot;Deployment failed&quot;);<br>        return true;<br>    }<br><br>    log.info(&quot;Deployment successful&quot;);<br>    return false;<br>}<br><br>private void sendEmail(String s) {<br>    if (!config.sendEmailSummary()) {<br>        log.info(&quot;Email disabled&quot;);<br>        return;<br>    }<br><br>    log.info(&quot;Sending email&quot;);<br>    emailer.send(s);<br>}</pre><h3>Final Thoughts</h3><p>Often when refactoring, it’s tempting to reach straight for techniques which break our code down into small, digestible pieces (e.g. <em>extract method</em>). If the bigger pieces (i.e. the three top-level if blocks in the example in the article) that we are breaking down are tightly coupled to each other, then breaking each of them down independently leave things even more tangled. A way to avoid this is to bring the coupled pieces of code together first — even if this introduces duplication — and then start to address the duplications once the coupling is localised.</p><p>I hope you found this useful and maybe have a go at the kata yourself ;-)</p><h3>Resources</h3><ul><li><a href="https://github.com/tomphp/untangled-conditionals-kata">The Untangled Conditionals Kata</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cc5693b8ec3c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/refactoring-untangling-conditionals-cc5693b8ec3c">Refactoring — Untangling Conditionals</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is Event Sourcing?]]></title>
            <link>https://medium.com/cloudnative-ly/what-is-event-sourcing-d201ed740451?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/d201ed740451</guid>
            <category><![CDATA[software-architecture]]></category>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[domain-driven-design]]></category>
            <category><![CDATA[event-sourcing]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Thu, 20 Feb 2020 11:23:13 GMT</pubDate>
            <atom:updated>2023-07-17T09:36:20.916Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/960/0*Me9NF-8IBwyFimoC.jpg" /><figcaption>Image credit: <a href="https://pixabay.com/illustrations/time-time-management-stopwatch-3216244/">geralt</a> via <a href="https://pixabay.com/illustrations/time-time-management-stopwatch-3216244/">Pixabay</a>.</figcaption></figure><p>In this article, I want to give a basic introduction to what Event Sourcing is, and share some thoughts from the community about deciding if it’s right for your project.</p><p>I’ve had a keen interest in event sourcing for several years, however, in the last two years I was not actively following the community. In that time I’ve seen some posts and articles popping up on social media with tales of event sourcing, but not in the way that I understood it. Often it would seem that I was reading about Event Driven Architectures with a Kafka log stored somewhere.</p><p>I felt like I had fallen behind the times and that maybe Event Sourcing had evolved. When DDD Europe 2020 announced that they were going to hold a one day, pre-conference conference on Event Sourcing, I jumped at the chance to get back up to speed. After attending this event (and the fabulous DDD Europe main conference) I was happy to learn that Event Sourcing is still what I knew it to be. More importantly, I also learned some valuable lessons from the advice and experience shared in the talks.</p><h3>What Event Sourcing is</h3><p>In the opening keynote at the event sourcing conference, <a href="https://twitter.com/UdiDahan">Udi Dahan</a> said:</p><blockquote>Event sourcing refers to a collection of patterns based on persisting the full history of a domain as a sequence of “events”, rather than persisting just the current state.</blockquote><h4>Storing Events</h4><p>With event sourcing, we store a record of any event that changes the state, <em>rather</em> than the resulting state after the event occurred. Events are stored as immutable pieces of data that record what event happened, along with any data that is relevant to that event. Events are immutable because they represent something that has already happened (you cannot change the past). As such, they are named as actions in the past tense, e.g. <em>OrderPlaced, PaymentTaken</em>, <em>OrderShipped.</em></p><p>Events are stored in <em>streams</em>, with a stream of events representing the entire history of a particular entity (or <em>Aggregate</em> in DDD terminology). These event streams are the source of truth for the state of the aggregate.</p><p>Once actions have been performed on the aggregate, we need to be able to get the events out to persist them in the event store.</p><p>As an example, I’m going to use an Order aggregate from an e-commerce system. You can <strong>create</strong> an order, <strong>add items</strong> to it, and then <strong>place</strong> it. Below you can see the public methods which perform these actions. In addition, there is also retrieveNewEvents()which will return all new events that have been generated since the object instance was constructed. These events can then be persisted to the event store.</p><pre>public class Order {<br>    public static Order create(OrderID orderID) {<br>        // Create a new Order (generates OrderCreated)<br>    }<br><br>    public void addItem(ItemCode item) {<br>        // Add an item to the order (generates ItemAdded)<br>    }<br><br>    public void place() {<br>        // Place the order (generates OrderPlaced)<br>    }<br><br>    public List&lt;OrderEvent&gt; retrieveNewEvents() {<br>        // Return all new events have have been generated<br>    }<br><br>    // ...<br>}</pre><h4>Replaying an Event Stream</h4><p>To load an event sourced aggregate’s state into memory, the stored events need to be replayed in order. To be able to do this, we need need to have another constructors for the aggregate which takes the stream of events</p><pre>public class Order {<br>    public static Order fromEventStream(ArrayList&lt;OrderEvent&gt; {<br>        // Create new Order and replay events to get the state<br>    }<br><br>    // ...<br>}</pre><p>We now have two constructors:</p><ol><li>create() creates a brand new order and adds an initial OrderCreated event to the list of new events.</li><li>fromEventStream() builds the current state from a stream of events. It also initialises the list of new events to an empty list.</li></ol><p>Let’s now take a look at a simplistic way that we might implement this. It is possible to refactor this code into a better state, but I want to keep it as simple as possible to highlight the key concepts.</p><p>To start with, let’s look at the state in the Order class:</p><pre>private ArrayList&lt;OrderEvent&gt; newEvents = new ArrayList&lt;&gt;();<br><br>private OrderID id;<br>private HashMap&lt;ItemCode, Quantity&gt; lines = new HashMap&lt;&gt;();<br>private boolean placed = false;</pre><p>id, lines and placed are the current state of the aggregate, while newEvents is used to keep a track of events as they occur.</p><p>Let’s now see that how the create() constructor works:</p><pre>public static Order create(OrderID orderID) {<br>    var orderCreated = new OrderCreated(orderID);<br>    var events = Collections.singletonList(orderCreated);<br>    var order = Order.fromEventStream(new ArrayList&lt;&gt;(events));<br>    order.newEvents.add(orderCreated);<br>    return order;<br>}</pre><p>The code above creates a new stream, containing a single OrderCreated event, and then creates the Order from that stream. This shows that actually fromEventStream() is the important constructor. The only other thing that create() does is save the event to newEvents.</p><p>Now let’s look at fromEventStream():</p><pre>public static Order fromEventStream(ArrayList&lt;OrderEvent&gt; events) {<br>    return new Order(events);<br>}<br><br>private Order(ArrayList&lt;OrderEvent&gt; events) {<br>    if (events.size() == 0) {<br>        throw new EmptyEventStream();<br>    }<br><br>    if (!(events.get(0) instanceof OrderCreated)) {<br>        throw new InvalidEvent(<br>                &quot;The first event must be OrderCreated&quot;<br>        );<br>    }<br><br>    for (OrderEvent event : events) {<br>        applyEvent(event);<br>    }<br>}</pre><p>We see that fromEventStream() just delegates through to a private constructor. The private constructor does a few checks on the event stream and then iterates over it, calling applyEvent() with each event.</p><p>applyEvent() is a private method that takes all event types and mutates the state accordingly. Here I have implemented it with an overloaded method and a nasty switch statement to check the event type. There are better ways to do this but it keeps the example simple:</p><pre>private void applyEvent(OrderEvent event) {<br>    if (event instanceof OrderCreated) {<br>        applyEvent((OrderCreated) event);<br>    } else if (event instanceof ItemAdded) {<br>        applyEvent((ItemAdded) event);<br>    } else if (event instanceof OrderPlaced) {<br>        applyEvent((OrderPlaced) event);<br>    }<br>}<br><br>private void applyEvent(OrderCreated event) {<br>    id = event.id;<br>}<br><br>private void applyEvent(ItemAdded event) {<br>    if (placed) {<br>        throw new OrderHasAlreadyBeenPlaced(id);<br>    }<br><br>    var quantity = lines.containsKey(event.itemCode)<br>            ? lines.get(event.itemCode).increment()<br>            : Quantity.of(1);<br><br>    lines.put(event.itemCode, quantity);<br>}<br><br>private void applyEvent(OrderPlaced event) {<br>    if (placed) {<br>        throw new OrderHasAlreadyBeenPlaced(id);<br>    }<br><br>    if (lines.isEmpty()) {<br>        throw new OrderHasNoItems(id);<br>    }<br><br>    placed = true;<br>}</pre><p>We have now seen how our event sourced aggregate’s state can be created from a stream of events. The final piece of the puzzle is how we create new events. With all the internal event driven infrastructure in place, this is very easy:</p><pre>public void addItem(ItemCode item) {<br>    OrderEvent event = new ItemAdded(item);<br>    applyEvent(event);<br>    newEvents.add(event);<br>}<br><br>public void place() {<br>    OrderEvent event = new OrderPlaced();<br>    applyEvent(event);<br>    newEvents.add(event);<br>}</pre><p>Now we have the complete example, I hope that it’s clear what event sourcing is. This example has been highly trivialised though, the core concepts are clear but event sourcing brings a lot of new complexity; for example:</p><ul><li>How do you deal with conflicts when you try and save new events but someone else has saved some new ones before you?</li><li>How do you version events? Since they are immutable, the old versions still need to be understood by the system.</li><li>What about performance when you have large event streams?</li><li>How do you delete sensitive data from the history (e.g. comply with GDPR)?</li></ul><p>The answers to these questions are beyond this scope of this article, but it’s important to know that the simple concept of event sourcing brings a lot of new challenges.</p><p>You can find the complete code for the example <a href="https://github.com/tomphp/event-sourcing-example">here</a>.</p><h3>When to use Event Sourcing</h3><p>Now that we know what event sourcing is, when should we use it?</p><p>Interestingly, a fairly consistent message at the talks in the conference was a strong warning against <em>event sourcing all the things</em>. Once you start thinking in domain events it seems like everything should be event sourced because it maps to the way we experience reality. However, the complexities of implementing this powerful technique make it a trade-off that should be carefully considered.</p><p>First and foremost, you should consider what event sourcing gives you:</p><ul><li>A full audit log (also useful for understanding and debugging issues)</li><li>The ability to restore the system to any point in history</li><li>The ability to gather information retrospectively</li><li>Decoupling the state from what happened</li></ul><p>These all sound great, but the question is - <em>does the value event sourcing brings to your solution outweigh the challenges to implement it?</em></p><p>In addition to this, Udi also gave some guidance on where it’s appropriate to use event sourcing in his keynote. Firstly he defined event sourcing as “<em>a collection of patterns based on persisting the full history of a </em><strong><em>domain</em></strong><em>”.</em> He then talked about how event sourcing should be applied to just small, appropriate domains within your organisation. He used the following advice from the definition of a <em>domain model</em> in <a href="https://www.amazon.co.uk/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420">Patterns of Enterprise Application Architecture</a> to suggest how you might identify somewhere where implementing event sourcing might make sense:</p><blockquote>“Use where you have complicated and ever-changing business rules.”</blockquote><p>One other piece of guidance that Udi gave was, that event sourcing can be a good fit if you have a bi-temporal domain — that is, “<em>something happened, and, it is valid until…</em>”</p><h3>Event Source vs Event Driven Architecture</h3><p>One common theme of the talks during the conference were people sharing the lessons they’d learned and the mistakes that were made along the way. Amongst this advice, there were some common themes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_LK8jtHKWooJpMKXaq_0Cg.png" /></figure><p>The most common theme that I noticed throughout the talks was that often people confuse event sourcing with Event Driven Architectures. That is to say that the events were viewed as a means of communication between services. Event sourcing and Event Driven Architectures can be used together, but they are not the same thing.</p><p>The big problem with merging the two concepts comes when you start publishing your internal event sourced events as public messages to be consumed by other services. Doing so couples the internal domain to the external messaging. You may indeed want to store an OrderPlaced event and publish one to a message bus for other services to consume, but different information might need to be in these data structures. For example, the internal event stored event does not need to include many details because they are already in the event history. However, the OrderPlaced message might be the first public message to be published about this order and should contain all the relevant details (i.e. <em>order ID</em>, order line details<em>, etc.)</em></p><h3>In Conclusion</h3><p>Having a dedicated event sourcing conference is a great sign that event sourcing is something you should know about. One thing that appeared on a few slides during the conference was the Gartner Hype Cycle graph, with a suggestion that many people are somewhere between the <em>Peak of Inflated Expectations</em> and the <em>Trough of Disillusionment</em>. Meanwhile, the community leaders are guiding us to the <em>Plateau of Productivity</em>.</p><figure><img alt="Gartner hypecycle graph." src="https://cdn-images-1.medium.com/max/1024/0*_IzTFv5SSBNsMF4m.jpg" /><figcaption>Source: <a href="https://www.gartner.com/en/research/methodologies/gartner-hype-cycle">gartner.com</a></figcaption></figure><p>I hope this article has served as a useful and digestible introduction.</p><h3>References</h3><ul><li><a href="https://dddeurope.com/2020/">DDD Europe 2020</a></li><li><a href="https://www.slideshare.net/udidahan/udi-dahan-event-sourcing-keynote-ddd-eu">Slides from Udi Dahan’s keynote</a></li><li><a href="https://github.com/tomphp/event-sourcing-example">The example code used in this article</a></li><li><a href="https://github.com/keyvanakbary/cqrs-documents">Greg Young’s CQRS/ES PDF</a> — a great introduction to both CQRS &amp; event sourcing</li><li><a href="https://eventsourcery.com/">Event Sourcery</a> — a great event sourcing tutorial</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d201ed740451" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/what-is-event-sourcing-d201ed740451">What is Event Sourcing?</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Writing Code With A Clear Conscience]]></title>
            <link>https://medium.com/cloudnative-ly/writing-code-with-a-clear-conscience-3d63e39b943c?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/3d63e39b943c</guid>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-craftsmanship]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Mon, 04 Nov 2019 06:35:58 GMT</pubDate>
            <atom:updated>2019-11-04T06:35:58.325Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZE9CPvxvJth5vxBGPMH2Cw.jpeg" /><figcaption>Featured Image by <a href="https://pixabay.com/users/Activedia-665768/">Okan Caliskan</a> from <a href="https://pixabay.com/">Pixabay</a></figcaption></figure><p>A few days ago, I posted a simple tweet about how investing in design pays back very quickly. This led to a short conversation with <a href="https://twitter.com/Aamirio">Aamir Idrees</a>, about how much engineering is enough, before it starts to become over-engineering.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*heOYRTBoUxBsxiY4DPnX_Q.png" /></figure><p>In my response, I said a phrase which I don’t think I’ve used before: <em>“be sure to have a clear conscience on what you deliver”</em>. Thinking back on it, I realise that this is my perfect way to summarise how I decide if a piece of work is complete. Here, I’d like to explain what I mean in more detail.</p><h3>Having a Clear Conscience</h3><blockquote><em>clear conscience noun</em></blockquote><blockquote><em>a knowledge or belief that one has done nothing bad or wrong</em></blockquote><blockquote><a href="https://www.merriam-webster.com/dictionary/clear%20conscience">Definition from Merriam Webster</a></blockquote><p>To commit code with a clear conscience, you must believe that you have not done anything <em>bad</em> or <em>wrong</em> while creating it. To quantify whether this is true, we must first understand who might judge our work as being <em>bad</em> or <em>wrong</em>. I’m going to generalise these people into three groups:</p><ul><li>People who benefit from the running software</li><li>The people investing in your work</li><li>Other developers</li></ul><p>I now want to look at our obligations to each of these groups:</p><h3>The People Who Benefit From the Running Application</h3><p>I’ve intentionally made the description of this group a bit vague. It could refer to the <em>end-users</em> of the software, they obviously benefit from using the software (otherwise why would they use it?). However, there many other people in this category. For example:</p><ul><li>It could also be people downstream from the end-users (e.g. as a customer of a telephone network, I benefit from the CRM that their support staff are using when I call up to query about my account).</li><li>It could be the people who are paying you to develop the software. The software may be the only reason they have a business.</li><li>It could even be you and the other developers, your job may be based on the success of the software.</li></ul><p>Regardless of who benefits from the running software, your obligation to them is to build software which performs at a satisfactory level and does not cause any harm (e.g. loss of money, physical or emotional harm, loss of productivity, etc.).</p><p>This gives us the first question to ask yourself when delivering a feature:</p><blockquote><em>Could this feature have any impact on the software which might cause distress to the people who benefit from it?</em></blockquote><p>Some things to consider when answering this question are:</p><ul><li><em>Are you confident that the users will be able to use it?</em></li><li><em>Are you confident that the changes haven’t broken the system elsewhere?</em></li><li><em>Do you have SLAs,</em><a href="http://localhost:4000/blog/writing-code-with-a-clear-conscience#fn:2"><em>2</em></a><em> SLOs</em><a href="http://localhost:4000/blog/writing-code-with-a-clear-conscience#fn:3"><em>3</em></a><em> and SLIs</em><a href="http://localhost:4000/blog/writing-code-with-a-clear-conscience#fn:4"><em>4</em></a><em> that you meet and track?</em></li></ul><h3>The People Investing in Your Work</h3><p>Hopefully, you are being paid to write code. Hopefully, you are being paid well to write code. If this is the case, then the people paying you are paying for a reason — they want a return on their investment. The tricky part here is that not only should you deliver working features on time, but you also need to deliver them in a way which doesn’t hinder further development later on.</p><p>The question here is one you should be asking daily:</p><blockquote><em>Am I doing a professional job while keeping a clear focus on what I’m trying to deliver?</em></blockquote><p>The key factors to enabled you to consistently answer <em>yes</em> to this question, are:</p><ul><li><em>Reviewing performance retrospectively, and applying learnings from these experiences.</em></li><li><em>Clearly communicating progress and challenges to manage expectations.</em></li><li><em>Architecting software with a view to the future; enabling accurate understanding for future tasks.</em></li></ul><h3>Other developers</h3><p>As part of a team, everyone should help each other succeed. By creating good quality as sustainable code, can help your team achieve their goals. Confusion or misleading code can cause other developers to loose hours trying to understand it. Tangled or tightly coupled code can be very hard to extend. Missing tests make it hard to be confident that your changes work. To have a clear conscience, we should deliver code that other team members will enjoy working with.</p><p>The question we should ask ourselves here is:</p><blockquote><em>Is my code going to make the work on future features harder?</em></blockquote><p>This time, I’m going to go a bit deeper into each of the factors which contribute to delivering high-quality code.</p><h3>Testing</h3><p>Tests enable other developers (or our future selves) to change and extend the system with confidence. Having a good quality test suite helps us avoid wasting unnecessary time checking that we haven’t inadvertently broken something.</p><p>To have a clear conscience, you should ask yourself <em>“If something is changed that would alter the behaviour of the system, will a test fail?”</em></p><p>There are cases when it’s acceptable to have some code which is not tested. An example might be where the gain of testing the integration with an external system does not outweigh the effort. In such a case, we can still ask how we will know when it fails (monitoring may be) and have we sufficiently handled failure. But we should also make an effort to isolate such code so that it’s easy to identify should a failure occur.</p><p>Regardless of the specifics of testing, a clear conscience comes from knowing you have protected the code from inadvertent damage, and enabled developers to continue to develop the system.</p><h3>Formatting</h3><p>Having a consistent formatting style in a project reduces the cognitive load for the people reading it. When the layout is consistent, our eyes instinctively follow the code, and we don’t have to hunt so hard for the logic we are looking for.</p><p>Ask yourself <em>“Have I laid out my code in a way which is consistent to the project?”</em></p><p>The important thing is that the team chooses a coding style and everyone follows it. Better yet, use a linter to check/fix your code for you. It’s important that you code to the project’s coding style, not your own. Having a clear conscience is not about you thinking it’s perfect, rather, it’s about ensuring that it doesn’t frustrate your colleagues.</p><h3>Naming</h3><p>The name of the variables, methods, classes, etc. is one of the best ways that we can ensure other developers can understand what the intent of the code is. Unfortunately, choosing the right name can be one of the hardest decisions a developer has to make.</p><p>Ask yourself <em>“Have I named anything in a way which will cause confusion?”</em></p><p>If you can’t think of the perfect name then it’s not a problem (we have powerful refactoring tools at our fingertips which makes renaming things simple). It is a problem though if our names cause confusion or misunderstanding.</p><h3>Well Architected</h3><p>How we structure our programs has a huge impact on how future work is done. On one hand, we might be able to make something work as intended with a thousand lines of ifs, fors and gotos. On the other hand, we have a huge library of Design Patterns, SOLIDs, YAGNIs, Laws of Demeter, Object Calisthenics, the list goes on - and we know we should be using them all, but sometimes it seems like too much. So what’s the right amount?</p><p>The question is simple <em>“Will other developers curse my name when working with my code?”</em></p><p>We’ve all thought <em>“What was X thinking when they wrote this code!?”</em>. We’ve all been X. And worse still, we’ve all thought that about code where X was ourselves.</p><p>By considering if there’s anything in our code which might cause someone to ask this question, and fixing it before we deliver it, we can improve others lives and have a clear conscience.</p><p>Interestingly, the culture of the team can make a big difference to this question. If you’re working in a team of people who have a strong crafting culture, then a <a href="https://www.martinfowler.com/bliki/Yagni.html">YAGNI</a> approach can be the perfect way to deliver something. If you know that when someone picks up the code for the next feature, they will start to factor it into a shape which fits the evolving architecture, then this is probably the most efficient way to work. On the other hand, if the culture in the team doesn’t work this way, then you probably need to <em>engineer</em> the solution a bit more to ensure it guides other team members. However, in the latter case, I think efforts should be investing in improving the culture (and possibly skill level in the team).</p><p>Finally, we should make efforts to conform to the architecture of the project; it’s never fun trying to navigate some code which solved a problem in three different ways at the same time. At the same time, we shouldn’t be afraid to change the original architecture if we collectively agree it is a hindrance.</p><h3>Failure Cases</h3><p>Things fail, that’s a fact. If that failure causes distress to the end-users, then that’s a problem. If reported failures from end-users cannot be easily tracked down and diagnosed, then everyone suffers.</p><p>The obvious question here is <em>“Have I handled all failure cases sufficiently?”</em></p><p>This can involve many things, such as <em>handling nulls</em>, <em>catching exceptions</em>, <em>raising exceptions</em>, <em>displaying meaningful error messages</em>, etc.</p><h3>Other Factors</h3><p>There are also many other things which might be important to consider, depending on your specific circumstances:</p><ul><li>Security: <em>“Is my code secure?”</em>, <em>“Can any personal details be leaked?”</em>, <em>“Are the dependencies up to date?”</em>, etc.</li><li>Logging: <em>“Have I logged useful messages?”</em>, <em>“Have I logged at the right error level?”</em>, <em>“Am I logging any unnecessary noise?”</em>, etc.</li><li>Accessibility: <em>Does the design of the feature exclude anyone from using it?</em></li></ul><p>There are many more, but I’ll leave it up to you to decide what is appropriate for each situation.</p><h3>Summary</h3><p>To have a <em>clear conscience</em> you must deliver software which does not knowingly do <em>bad</em> or <em>wrong</em> things in the eyes of any of these groups of people. It is not possible to do this without considering all groups. If you over-engineer the perfect solution, then the developers might be very happy, but features might be very expensive to develop. Conversely, if you rush features out the door as quickly as possible, then developers are likely to get unhappy with working conditions, and end-users are likely to get unhappy with broken features.</p><p>With this in mind, the only way we can keep them all happy is by managing expectations; bending over backwards to make one person happy is likely to have negative effects on the other people.</p><p>It’s also worth noting that these choices are context-specific; many factors can determine what the minimum viable implementation looks like. Some of these include:</p><ul><li>Number of users using the system</li><li>The scale of the system, teams or organisation</li><li>Do the developers have the right tools (e.g. refactoring tools)</li></ul><p>I hope this article has provided some guidance towards keeping your conscience clear, while keeping productivity high.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3d63e39b943c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/writing-code-with-a-clear-conscience-3d63e39b943c">Writing Code With A Clear Conscience</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Haskell — Mapping with State]]></title>
            <link>https://medium.com/cloudnative-ly/haskell-mapping-with-state-7a07e3c2cbf9?source=rss-8b62695f2784------2</link>
            <guid isPermaLink="false">https://medium.com/p/7a07e3c2cbf9</guid>
            <category><![CDATA[monads]]></category>
            <category><![CDATA[kata]]></category>
            <category><![CDATA[articles]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[haskell]]></category>
            <dc:creator><![CDATA[Tom Oram]]></dc:creator>
            <pubDate>Mon, 28 Oct 2019 08:21:16 GMT</pubDate>
            <atom:updated>2019-10-28T08:21:16.264Z</atom:updated>
            <content:encoded><![CDATA[<h3>Haskell — Mapping With State</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sQaydo7FYx-CMzDO2b1-FQ.jpeg" /><figcaption>Featured photo by <a href="https://unsplash.com/@michellem18">Michelle McEwen</a> on <a href="https://unsplash.com/">Unsplash</a>.</figcaption></figure><p>These days, the functions map, filter and fold/reduce are pretty well known by most programmers. Any pure data manipulation performed in a loop can be re-written with a fold, but it’s not always easy to understand. We use map and filter when we can to make things clearer, and fold is useful when <em>folding</em> a collection down to a single value. However, for more complex loops, most would argue that an imperative loop is easier to understand than trying to wrap up all the state in the accumulator of a <em>fold</em>. In this article, we look at a situation where using fold to <em>map over a collection while maintaining state</em> can be clarified by mapping over a State monad.</p><h3>The Challenge</h3><p>The map function lets us transform each <em>element</em> in a list, like this:</p><pre>newList = map (+1) [1, 2, 3]<br><em>-- newList is [2, 3, 4]</em></pre><p>But what if we want to do something like this (Javascript):</p><pre><strong>function</strong> addAnIncrementingAmount(numbers) {<br>  <strong>let</strong> result = [];<br>  <strong>let</strong> amountToAdd = 0;</pre><pre>  <strong>for</strong> (<strong>const</strong> number <strong>of</strong> numbers) {<br>    result.push(number + amountToAdd);<br>    amountToAdd++;<br>  }</pre><pre>  <strong>return</strong> result;<br>}</pre><pre><strong>const</strong> newList = addAnIncrementingAmount([1, 2, 3]);<br><em>// newList is [1, 3, 5]</em></pre><p>Even though the result is a list <em>mapping</em> each element from an element provided in the argument, we are unable to use map because the calculation for each element is dependant on the previous one. Therefore, we have to use foldl instead:</p><pre>addAnIncrementingAmount :: [Int] -&gt; [Int]<br>addAnIncrementingAmount numbers =<br>  fst $ foldl addAmount addAmount ([], 0) numbers</pre><pre>addAmount :: ([Int], Int) -&gt; Int -&gt; ([Int], Int)<br>addAmount (result, amountToAdd) number =<br>  (result ++ [number + amountToAdd], amountToAdd + 1)</pre><p>While this code is fairly simple (because the example itself is very simple), if we had more stateful values used in the calculation then it would get more complex. Also, the addAmount is trying to do two things at once - i.e. build the resulting list and perform the calculations.</p><h3>Generalising with a new higher-order function</h3><p>Let’s start by separating the calculation from the <em>stateful mapping</em>. We can do this by creating a new mapWithState higher-order function.</p><pre>addAnIncrementingAmount :: [Int] -&gt; [Int]<br>addAnIncrementingAmount numbers = mapWithState addAmount 0 numbers</pre><pre>mapWithState :: (a -&gt; state -&gt; (b, state)) -&gt; state -&gt; [a] -&gt; [b]<br>mapWithState f state xs = fst $ foldl f ([], state) xs</pre><pre>addAmount :: Int -&gt; Int -&gt; (Int, Int)<br>addAmount number amountToAdd = (number + amountToAdd, amountToAdd + 1)</pre><p>This is a nice separation of concerns. The mapWithState function is concerned with building the resulting list and passing the state through, while the addAmount function is only concerned with our calculation. This is a good start, but it’s not clear in the type of addAmount which argument is the state and which is the element we are <em>mapping</em> - can we do something about that?</p><p>The type signature should give us a clue as to what we could try. The fact that it returns a tuple of (result, newState) should make us think about the State monad.</p><h3>The State Monad</h3><p>State is available via Control.Monad.State of the mtl<a href="http://tomphp.github.io/blog/haskell-mapping-with-state#fn:1">1</a> package. It is defined like this:</p><pre><strong>newtype</strong> State s a = State { runState :: State s a -&gt; s -&gt; a }</pre><p>And is used like this:</p><pre><strong>import</strong> <strong>Control.Monad.State</strong> (State, get, modify, put, evalState)</pre><pre>performCalculation :: Int -&gt; Int<br>performCalculation n = evalState statefulCalculation n</pre><pre>statefulCalculation :: State Int Int<br>statefulCalculation = <strong>do</strong><br>  initalValue &lt;- get<br>  put (initialValue + 3)<br>  modify (*2)<br>  newValue &lt;- get <br>  return (newValue - initalValue)</pre><p>Which would be be the equivilent to this in Javascript:</p><pre><strong>function</strong> performCalculation(initalValue) {<br>  <strong>let</strong> newValue = initalValue + 3<br>  newValue = newValue * 2<br>  <strong>return</strong> (newValue - initalValue)<br>}</pre><p>While the example above isn’t particularly beautiful, I hope it provides enough information about using the State monad for our example. One additional point about State (or any other monad) is that its context is maintained through functional calls within the monad. Let’s see that:</p><pre><strong>import</strong> <strong>Control.Monad.State</strong> (State, get, modify, put, evalState)</pre><pre>performCalculation :: Int -&gt; Int<br>performCalculation n = evalState statefulCalculation n</pre><pre>statefulCalculation :: State Int Int<br>statefulCalculation = <strong>do</strong><br>  initalValue &lt;- get<br>  add 3<br>  multiply 2<br>  newValue &lt;- get <br>  return (newValue - initalValue)</pre><pre>add :: Int -&gt; State Int ()<br>add amount = modify (+amount)</pre><pre>multiply :: Int -&gt; State Int ()<br>multiply amount = modify (*amount)</pre><h3>Back to our example</h3><p>Now we know about the State monad, let’s try re-writing the addAmount function to use it:</p><pre>addAmount :: Int -&gt; State Int Int<br>addAmount number = <strong>do</strong><br>  amountToAdd &lt;- get<br>  modify (+1)<br>  return (number + amountToAdd)</pre><p>Now the type tells us something interesting about the function — <em>it takes an Int and returns an Int, but it also maintains some state (also of type Int)</em>. But how do we use it?</p><h3>Traversable</h3><p>We know that we want to our addAmount function map over our input list, so what do we get if we try that now?</p><pre>Prelude Control.Monad.State&gt; :t map addAmount [1, 2, 3]<br>map addAmount [1, 2, 3] :: [State Int Int]</pre><p>We’ve individually added each element into a State and ended up with [State Int Int], but that’s not what we need, we want to compute the entire list inside State - i.e. State Int [Int]. Wouldn’t it be great if there was a simple function to convert from what we have into what we want - i.e. [State Int Int] -&gt; State Int [Int].</p><p>It turns out that lists implement the typeclass Traversable. If we look at the definition of Traversable then we see this:</p><pre><strong>class</strong> (Functor t, Foldable t) =&gt; Traversable (t :: * -&gt; *) <strong>where</strong><br>  traverse :: Applicative f =&gt; (a -&gt; f b) -&gt; t a -&gt; f (t b)<br>  sequenceA :: Applicative f =&gt; t (f a) -&gt; f (t a)<br>  mapM :: Monad m =&gt; (a -&gt; m b) -&gt; t a -&gt; m (t b)<br>  sequence :: Monad m =&gt; t (m a) -&gt; m (t a)</pre><p>If we represent our list with Traversable t and our State monad with Monad m, then the function we after would have the type t (m a) -&gt; m (t a) - that’s exactly the type of sequence in the typeclass above! Let’s try using it:</p><pre>addAnIncrementingAmount :: [Int] -&gt; [Int]<br>addAnIncrementingAmount numbers =<br>  evalState (sequence (map addAmount numbers)) 0</pre><pre>addAmount :: Int -&gt; State Int Int<br>addAmount number amountToAdd number = <strong>do</strong><br>  amountToAdd &lt;- get<br>  modify (+1)<br>  return (number + amountToAdd)</pre><p>This works exactly as expected. In fact, this combination of map and sequence is so useful, that if we look at the type signatures long enough, we see that mapM in Traversable is the composition of these two functions:</p><pre>mapM :: (a -&gt; m b) -&gt; t a -&gt; m (t b)</pre><p>Let’s try mapM:</p><pre>addAnIncrementingAmount :: [Int] -&gt; [Int]<br>addAnIncrementingAmount numbers =<br>  evalState (mapM addAmount numbers) 0</pre><pre>addAmount :: Int -&gt; State Int Int<br>addAmount number amountToAdd number = <strong>do</strong><br>  amountToAdd &lt;- get<br>  modify (+1)<br>  return (number + amountToAdd)</pre><p>At this point, I hope that I’ve managed to practically show how State and mapM can be used together without digging too deeply into the details (there’s plenty of excellent resources on this elsewhere <a href="http://tomphp.github.io/blog/haskell-mapping-with-state#fn:2">2</a>). However, my example so far is not that useful, let’s look at something a bit more complex.</p><h3>The Bowling Game Kata</h3><p>The <a href="https://kata-log.rocks/bowling-game-kata">Bowling Game Kata</a> is a well-know Test-Driven Development exercise where the goal is to calculate the score of a game of ten-pin bowling.</p><p>A typical Javascript solution might look something like this:</p><pre><strong>class</strong> Game {<br>  <strong>constructor</strong>() {<br>    <strong>this</strong>.rolls = [];<br>  }</pre><pre>  roll(pins) {<br>    <strong>this</strong>.rolls.push(pins);<br>  }</pre><pre>  score() {<br>    <strong>let</strong> score = 0;<br>    <strong>let</strong> framePointer = 0;</pre><pre>    <strong>for</strong> (<strong>const</strong> frame <strong>of</strong> Array(10).keys()) {<br>      <strong>if</strong> (<strong>this</strong>.isStrike(framePointer)) {<br>        score += <strong>this</strong>.scoreStrike(framePointer);<br>        framePointer += 1;<br>      } <strong>else</strong> <strong>if</strong> (<strong>this</strong>.isSpare(framePointer)) {<br>        score += <strong>this</strong>.scoreSpare(framePointer);<br>        framePointer += 2;<br>      } <strong>else</strong> {<br>        score += <strong>this</strong>.scoreNormalFrame(framePointer);<br>        framePointer += 2;<br>      }<br>    }</pre><pre>    <strong>return</strong> score;<br>  }</pre><pre>  isStrike(framePointer) {<br>    <strong>return</strong> <strong>this</strong>.rolls[framePointer] === 10;<br>  }</pre><pre>  isSpare(framePointer) {<br>    <strong>return</strong> <strong>this</strong>.rolls[framePointer] + <strong>this</strong>.rolls[framePointer + 1] === 10;<br>  }</pre><pre>  scoreStrike(framePointer) {<br>    <strong>return</strong> 10 + <strong>this</strong>.rolls[framePointer + 1] + <strong>this</strong>.rolls[framePointer + 2];<br>  }</pre><pre>  scoreSpare(framePointer) {<br>    <strong>return</strong> 10 + <strong>this</strong>.rolls[framePointer + 2];<br>  }</pre><pre>  scoreNormalFrame(framePointer) {<br>    <strong>return</strong> <strong>this</strong>.rolls[framePointer] + <strong>this</strong>.rolls[framePointer + 1];<br>  }<br>}</pre><p>The score function has a for loop in it so this is the bit which will need to be re-written to convert it to Haskell. Let’s start by extracting the scoring of each frame and then add up the results at the end.</p><pre>score() {<br>    <strong>let</strong> frameScores = [];<br>    <strong>let</strong> framePointer = 0;</pre><pre>    <strong>for</strong> (<strong>const</strong> frame <strong>of</strong> Array(10).keys()) {<br>      <strong>const</strong> [frameScore, rollsInFrame] = <strong>this</strong>.scoreFrame(framePointer);<br>      frameScores.push(frameScore);<br>      framePointer += rollsInFrame;<br>    }</pre><pre>    <strong>return</strong> frameScores.reduce((score, frameScore) =&gt; score + frameScore);<br>  }</pre><pre>  scoreFrame(framePointer) {<br>    <strong>if</strong> (<strong>this</strong>.isStrike(framePointer)) {<br>      <strong>return</strong> [<strong>this</strong>.scoreStrike(framePointer), 1];<br>    } <strong>else</strong> <strong>if</strong> (<strong>this</strong>.isSpare(framePointer)) {<br>      <strong>return</strong> [<strong>this</strong>.scoreSpare(framePointer), 2];<br>    } <strong>else</strong> {<br>      <strong>return</strong> [<strong>this</strong>.scoreNormalFrame(framePointer), 2];<br>    }<br>  }</pre><p>Now we’ve extract scoreFrame we can convert it to Haskell by replacing the for loop with a foldl (the implementation below isn’t like for like, but it’s close enough):</p><pre>score :: [Int] -&gt; Int<br>score rolls = sum $ fst $ foldl scoreFrame ([], rolls) [1..10]</pre><pre>scoreFrame :: ([Int], [Int]) -&gt; Int -&gt; ([Int], [Int])<br>scoreFrame state@(frameScores, rolls) _frame<br>  | isStrike rolls = scoreStrike state<br>  | isSpare rolls  = scoreSpare state<br>  | otherwise      = scoreNormal state</pre><pre>isStrike :: [Int] -&gt; Bool<br>isStrike rolls = allPins $ scoreRolls 1 rolls</pre><pre>isSpare :: [Int] -&gt; Bool<br>isSpare rolls = allPins $ scoreRolls 2 rolls</pre><pre>scoreStrike :: ([Int], [Int]) -&gt; ([Int], [Int])<br>scoreStrike (frameScores, rolls) =<br>  (frameScores ++ [scoreRolls 3 rolls], moveFrame 1 rolls)</pre><pre>scoreSpare :: ([Int], [Int]) -&gt; ([Int], [Int])<br>scoreSpare (frameScores, rolls) =<br>  (frameScores ++ [scoreRolls 3 rolls], moveFrame 2 rolls)</pre><pre>scoreNormal :: ([Int], [Int]) -&gt; ([Int], [Int])<br>scoreNormal (frameScores, rolls) =<br>  (frameScores ++ [scoreRolls 2 rolls], moveFrame 2 rolls)</pre><pre>scoreRolls :: Int -&gt; [Int] -&gt; Int<br>scoreRolls numRolls rolls = sum $ take numRolls rolls</pre><pre>moveFrame :: Int -&gt; [Int] -&gt; [Int]<br>moveFrame numRolls rolls = drop numRolls rolls</pre><pre>allPins :: Int -&gt; Bool<br>allPins = (== 10)</pre><p>We can see here that there’s a lot of confusing looking type signatures. Although this could be greatly improved by using explicit types rather than Int everywhere, there is still a lot of noise from having to manually thread the state through everywhere.</p><h3>Refactoring to Use State</h3><p>Now lets take a look at a version which makes use of State:</p><pre><strong>import</strong> <strong>Control.Monad</strong> (mapM)<br><strong>import</strong> <strong>Control.Monad.State</strong> (State, get, put, modify, evalState)<br><strong>import</strong> <strong>Control.Conditional</strong> (condM, otherwiseM)</pre><pre>score :: [Int] -&gt; Int<br>score rolls = sum $ evalState (mapM scoreFrame [1..10]) rolls</pre><pre>scoreFrame :: Int -&gt; State [Int] Int<br>scoreFrame _frame =<br>  condM [ (isStrike,   scoreStrike)<br>        , (isSpare,    scoreSpare)<br>        , (otherwiseM, scoreNormal)<br>        ]</pre><pre>isStrike :: State [Int] Bool<br>isStrike = allPins &lt;$&gt; scoreRolls 1</pre><pre>isSpare :: State [Int] Bool<br>isSpare = allPins &lt;$&gt; scoreRolls 2</pre><pre>scoreStrike :: State [Int] Int<br>scoreStrike = <strong>do</strong><br>  score &lt;- scoreRolls 3<br>  moveFrame 1<br>  return score</pre><pre>scoreSpare :: State [Int] Int<br>scoreSpare = <strong>do</strong><br>  score &lt;- scoreRolls 3<br>  moveFrame 2<br>  return score</pre><pre>scoreNormal :: State [Int] Int<br>scoreNormal = <strong>do</strong><br>  score &lt;- scoreRolls 2<br>  moveFrame 2<br>  return score</pre><pre>scoreRolls :: Int -&gt; State [Int] Int<br>scoreRolls numRolls = sum . take numRolls &lt;$&gt; get</pre><pre>moveFrame :: Int -&gt; State [Int] ()<br>moveFrame numRolls = modify (drop numRolls)</pre><pre>allPins :: Int -&gt; Bool<br>allPins = (== 10)</pre><p>While there are a few bits in this version which require some understanding, it does remove a lot of the clutter from the previous version. It also makes a clear separation between the state and the frame number itself (which incidentally is never actually used).</p><h3>Final Worlds</h3><p>I don’t claim that using mapM instead of foldl is always clearer, and I don’t claim that either of the implementations of the Bowling Game scoring exercise above is the best way to solve this in Haskell, but I do hope you have enjoyed this article and perhaps learned something new along the way.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7a07e3c2cbf9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/cloudnative-ly/haskell-mapping-with-state-7a07e3c2cbf9">Haskell — Mapping with State</a> was originally published in <a href="https://medium.com/cloudnative-ly">Cloudnative.ly</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>