<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Matt.si</title><description>Mattsi Jansky&apos;s personal programming/tech blog</description><link>https://www.matt.si/</link><item><title>Deterministic(ish) Machine Configuration with Python</title><link>https://www.matt.si/2026-04/dotfiles/</link><guid isPermaLink="true">https://www.matt.si/2026-04/dotfiles/</guid><description>Implementing deterministic(ish) machine configuration without resorting to Nix, using Python scripting</description><pubDate>Wed, 01 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I finished a 2-month project, and as I always do between projects I wiped my machine. Next, I of course needed to set up my machine with all my configurations and tooling, which I’d typically do by running my dotfiles. But, my dotfiles are a bit old and borked, and since I’m on the bench now… I figured, why not do a bit of &lt;a href=&quot;https://thedecisionlab.com/biases/bikeshedding&quot;&gt;bike shedding&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;The goal of my new dotfiles is largely the same as before: Deterministic(ish) machine configuration. I should be able to run a single command, type in my password, and have almost all the usual setup and configuration I’d need for my day-to-day work done, just like that. When something breaks, I should be able to look through the history of my dotfiles to see when certain configuration changes were introduced and why. In short, it should be a source of ‘development environment as code’.&lt;/p&gt;
&lt;p&gt;It is common wisdom that you should practice the parts of your work that are unfamiliar or infrequent, so that you are fully prepared when the time comes that you need them. You can see this principle in &lt;a href=&quot;https://en.wikipedia.org/wiki/Chaos_engineering&quot;&gt;chaos engineering&lt;/a&gt;, in which we try to become more comfortable with disaster recovery and make such practices a normal day-to-day event, so that we’ll be perfectly comfortable and ready when a big disaster outside of our control comes along. I think of my development environment the same way: I frequently wipe my machine and automate my configuration because I want to be extremely comfortable setting it up again quickly. It shouldn’t be a time-consuming ordeal to swap to a new machine, or to reset yours for one reason or another.&lt;/p&gt;
&lt;p&gt;My original implementation was very much inspired by &lt;a href=&quot;https://github.com/atomantic/dotfiles&quot;&gt;Adam Eivy’s dotfiles&lt;/a&gt;. But the Bash version I’d hacked together using bits and pieces from Adam’s repo didn’t hold up, it seemed to drift quickly and often presented awkward weird bugs as you’d expect from Bash. The functions for printing the output weren’t very well encapsulated so different steps might behave significantly differently. It just wasn’t very maintainable or easy to work with. I’d had the idea in mind for a while to rewrite this in Python, and here it is:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Alt text&quot; loading=&quot;lazy&quot; width=&quot;594&quot; height=&quot;603&quot; src=&quot;https://www.matt.si/_astro/dotfiles-output.ByLfeGEY_22J01Q.webp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It isolates each individual setup step, grouping related ones together but printing out the results of individual steps as soon as they are finished, so you get immediate feedback. Icons indicate success, skip, or failure. Steps should be idempotent, and skip execution if they can detect that they’ve already run. Console output is swallowed, unless an error occurs:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:600px;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2026-04/dotfiles/dotfiles-output-error.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2026-04/dotfiles/dotfiles-output-error.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;   
&lt;p&gt;This way, when I run the thing some years down the line and some step has inevitably broken as software changes and times change, I can clearly see what is going on.&lt;/p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;
&lt;p&gt;The code lives &lt;a href=&quot;https://github.com/mattsi-jansky/dotfiles.new&quot;&gt;here&lt;/a&gt; and is separated into core/framework code, steps, and home files:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;      # configuration files for specific apps&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; framework&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;   # Pretty printing, abstractions around &apos;steps&apos;, core logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; home&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;        # home dir dotfiles (`.bashrc`, etc)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; steps&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;       # The individual steps to run during setup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; tests&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;       # Tests for the framework&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To add a new step you can write any arbitrary code inside a &lt;code&gt;runner&lt;/code&gt; decorator:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;@runner&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;step&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75;font-style:italic&quot;&gt;group&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;Nushell&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E06C75;font-style:italic&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;Install Nushell&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; install_nushell&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() -&amp;gt; Result:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; cargo_install&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;nu&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You return a result, and the framework formats and prints it for you. You can pass &lt;code&gt;interactive=True&lt;/code&gt; to mark a step as needing interactivity (i.e. the step needs user input), and &lt;code&gt;group&lt;/code&gt; groups different steps together under headers. For actually doing something inside your steps there are several helper functions or ‘providers’ for doing common things like installing apt, snap or cargo packages, creating symbolic links, or running shell commands and interpreting the results.&lt;/p&gt;
&lt;h2 id=&quot;automatically-registering-github-ssh-keys&quot;&gt;Automatically registering GitHub SSH keys&lt;/h2&gt;
&lt;p&gt;I find an intrinsic pleasure in automating something that would otherwise be an awkward inconvenience (&lt;a href=&quot;https://xkcd.com/1319/&quot;&gt;XKCD 1319&lt;/a&gt; notwithstanding), and one of those inconveniences is creating a new SSH key every time I set up a new development environment. I want to start exploring GitHub alternatives more, but for now it is what I use, and so I automated away this dull task using GitHub CLI.&lt;/p&gt;
&lt;p&gt;I have a step that generates an SSH key, an interactive step that ensures you are authorised with GitHub CLI, and a step that uses the GitHub CLI to upload your SSH key for you. I doubt that I’ll win back the amount of time spent doing this for years if not decades but it was very satisfying to run my dotfiles then push to my dotfiles over SSH, without ever setting up a key manually. I just wanted to highlight that because I’m particularly happy with it.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Solved! I’m sure I’ll never have to worry about machine configuration again, right? …Right?&lt;/p&gt;
&lt;p&gt;If this sounds cool to you too, feel free to have a play with &lt;a href=&quot;https://github.com/mattsi-jansky/dotfiles.new&quot;&gt;the code&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>&apos;Rust 101: Understand the Hype (Devoxx UK)&apos;</title><link>https://www.matt.si/2024-05/devoxx-uk-24/</link><guid isPermaLink="true">https://www.matt.si/2024-05/devoxx-uk-24/</guid><description>Rust is an up-and-coming, safe and performant programming language with some very novel, funky features. But, most developers don&apos;t know why Rust is so talked about. What makes it different? Suitable to anyone with basic programming knowledge, beginner-friendly.</description><pubDate>Thu, 23 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I was lucky enough to talk at &lt;a href=&quot;https://www.devoxx.co.uk&quot;&gt;Devoxx UK&lt;/a&gt;, about one of my favourite subjects! I had a great time, the talk was very well recieved and thanks to an amazing AV team we have a great recording of it too. Check it out:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/DO4jJ1O3Cq4&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title>Large Language Models Are Drunk at the Wheel</title><link>https://www.matt.si/2024-02/llms-overpromised/</link><guid isPermaLink="true">https://www.matt.si/2024-02/llms-overpromised/</guid><description>Since ChatGPT we&apos;ve seen huge amounts of interest in Large Language Models, branded as &quot;AI&quot;. Their overpromised claims, uncritically repeated by a naive media, have been a major source of confusion and misunderstanding. Let us examine what these things can actually do, what they can&apos;t, and why yet another exaggerated tech industry fad may blow up in our faces again.</description><pubDate>Thu, 22 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As an Artificial Intelligence proponent, I want to see the field succeed and go on to do great things. That is precisely why the current exaggerated publicity and investment around “AI” concerns me. I use quotation marks there because what is often referred to as AI today is not whatsoever what the term once described. The recent surge of interest in AI owing to Large Language Models (LLMs) like ChatGPT has put this vaguely defined term at the forefront of dialogue on technology. But LLMs are not meaningfully intelligent (we will get into that), yet it has become common parlance to refer to these chatbots as AI&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Using the term AI can generate media buzz and interest in your business. But referring to your product as AI leaves the user with expectations that it is unlikely to fulfil. We will look at what LLMs can and can’t do, see that this trend in the industry is not new, and explore the implications this has for the tech industry.&lt;/p&gt;
&lt;h2 id=&quot;how-did-we-get-here&quot;&gt;How did we get here&lt;/h2&gt;
&lt;p&gt;When Turing published Computing Machinery and Intelligence, he described a “Thinking Machine” that could reason like humans do. He wrote an extensive argument that thinking machines were possible to create: That nothing known in physics, computing, mathematics, or any other field discounted the possibility. It iterated every known argument against thinking machines, thoroughly deconstructing and defeating each one. At the Dartmouth Conference in 1956 the idea of a thinking machine came to be known as Artificial Intelligence. There we humans took our first serious and organised steps toward creating one.&lt;/p&gt;
&lt;p&gt;Since then the AI field has generated a huge number of remarkable discoveries: Search, Knowledge Representation, Inference in First-Order Logic, Probabilistic Reasoning, Expert Systems, Dynamic Planning &amp;amp; Robotics, Multi-Agent Systems, Machine Learning, Speech Recognition, Natural Language Processing, Machine Translation, Image Recognition, and so forth. These technologies can be broadly categorised into three approaches: Connectionism, Symbolism, and Actionism.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/ai-subfields.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/ai-subfields.png&quot; alt=&quot;A diagram describing the three main areas of AI: Connectionism, which tries to create AI by simulating how real neurons work. Symbolism, which aims to use search to solve any arbitrary logical problems. And actionism, which focuses on creating useful, meaningful machines that can act in real time.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;A slide from a presentation I wrote, describing the three main areas of the AI field&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;where-are-we&quot;&gt;Where are we&lt;/h2&gt;
&lt;p&gt;In the public dialogue this nuance is overshadowed by LLMs, the one achievement of the AI field that everyone is talking about lately. An LLM is a machine learning algorithm that can generate believably human-like text. It is trained on enormous amounts of text using staggering amounts of processing power, to create a probabilistic model that can mostly predict what a real human person might say in response to a given input. This is done by creating neural networks, but don’t be confused: These neural networks are nothing like mammal brains. They are not intended to reproduce how humans &lt;em&gt;think&lt;/em&gt;, but rather to predict what a human might &lt;em&gt;say&lt;/em&gt; in response to a given input. Neural networks are involved in the mechanism, but not to simulate human-like thought. The primary means by which this all works is statistics and probability theory. In other words, the model guesses which combination of letters someone else may write in response to your prompt.&lt;/p&gt;
&lt;p&gt;In discussions of the philosophy and definition of AI, the following diagram is frequently used. It expresses the main four differing ways in which people define AI. Should AI think like we do? Or, should it produce logically correct answers? Does it have to be autonomous? Is there any value to how it &lt;em&gt;thinks&lt;/em&gt; so long as it &lt;em&gt;acts&lt;/em&gt; human-like? Is there any value to being &lt;em&gt;human-like&lt;/em&gt; so long as it produces valuable &lt;em&gt;actions&lt;/em&gt;?&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:50%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/thinking-acting-humanly-rationally.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/thinking-acting-humanly-rationally.png&quot; alt=&quot;A diagram showing the four differing categories for defining AI: Thinking humanly, acting humanly, thinking logically, and acting logically.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;This diagram is commonly used in discussions of the philosophy of AI to explore what AI is. Reproduced from Russel &amp;amp; Norvig.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If anywhere, LLMs would go firmly into the bottom-left of this diagram. They act humanly but they aren’t intended to act rationally, nor to think in human-like ways. You could be forgiven for thinking that they do a lot more than that. In this case, some of the most powerful machine learning models ever created have been given the task “produce something that appears human-like and intelligent” and they are incredibly good at it. But let us be clear: They are not intelligent. They are incapable of reasoning. Again, you could be forgiven for being surprised at that given how the media has treated LLMs as the beginning of the robot uprising. But don’t take my word for it: Professor Subbarao Kambhampati of the School of Computing &amp;amp; AI at Arizona State University wrote a brilliant article&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; that goes into much more detail than we will here, in which he concludes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;…nothing that I have read, verified or done gives me any compelling reason to believe that LLMs do reasoning/planning as it is normally understood. What they do, armed with their web-scale training, is a form of universal approximate retrieval which, as we have argued, can sometimes be mistaken for reasoning capabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For an easier-to-read “layman” explanation I recommend Spencer Torene’s (Computational Neuroscience PhD, Lead Research Scientist at Reuters) October article “Do LLMs Reason?”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-39&quot; id=&quot;user-content-fnref-39&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. In short, LLMs are like parrots. However, their behaviour frequently appears logical. This is because their training sets are so vast and the compute power dedicated to their training so enormous that they are often capable of retrieving (or parroting) a believable answer. But they do not perform the logical steps to actually solve the problem. As such they cannot solve novel problems, nor verify whether their answers are correct or incorrect.&lt;/p&gt;
&lt;p&gt;They are not the thinking machines that Turing envisioned. It might seem like I’m splitting hairs, but there is a big difference between real intelligence and the guesswork that LLMs do. They have no conception of knowledge, of truth or untruth: They cannot test whether what they are saying is correct or not. This is why they frequently fail very simple, obvious questions. Of course, the subtle truth here is that they are also frequently answering wrongly to complex, difficult questions but we are less likely to notice. The answers to complex questions take much more effort for us to verify. Our lazy, efficient brains are more likely to gloss over such details and assume it is correct. Hence why we notice these mistakes much more often when we ask simple, easily refutable questions.&lt;/p&gt;
&lt;p&gt;One great example recently was asking an LLM to tell you the name of a Greek philosopher beginning with M&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. Numerous people have tried this and time and time again LLMs will give you wrong answers insisting that Aristotle, or Seneca, or some other philosopher’s name begins with M. Yet, we can see right in front of us that it does not. Note how these chatbots speak with such confidence: They are exactly as certain about their answer when they are wrong, as when they are right. ChatGPT is still doing this now, and you can see an example I generated below.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:75%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/greek-philosophers.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/greek-philosophers.png&quot; alt=&quot;A conversation with ChatGPT in which it gives clearly incorrect answers to the aforementioned question&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;ChatGPT most likely is getting confused (insofar as we can attribute &quot;confusion&quot; to a mathematical model) about Thales of Miletus, who is named Thales and from Miletus. Miletus is not his name, and Thales does not begin with &quot;M&quot;.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Over time, the authors catch these problems and patch them. But not by changing the LLM itself. You can’t “fix” these problems in the LLM when you spot them because they are fundamental issues with LLMs as a concept. You might try to fix them by changing the training data, but that risks causing undesired changes in behaviour elsewhere in the practically infinite range of possible inputs. It has proven very difficult to train LLMs to do something specific. The vast amount of data they are trained on will always outweigh whatever small amounts of training data you add. You risk getting stuck in an endless whack-a-mole game with a model that is ultimately not capable of what you want from it.&lt;/p&gt;
&lt;p&gt;No, OpenAI and others are “fixing” them by introducing separate layers to the chatbot that use other non-LLM techniques. In the early days, for example, ChatGPT was hilariously bad at maths (of course it is: an LLM is not intended to and cannot solve logic problems) and would fail to answer even the most simple arithmetic. This was patched by passing off the problem to a typical calculator when an equation is detected. Whatever mechanism they use to detect equations does not always work however, so sometimes your maths prompts will get through to the LLM and it may respond with a completely wrong answer. You can do this by asking a logical question in an indirect way. For example, if you ask an arithmetic question referring to “the height of Shaquille O’Neal” (instead of saying 2.16 meters) ChatGPT tries and fails to answer it&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;infinite-possibilities-uncontrollable-chaos&quot;&gt;Infinite Possibilities, Uncontrollable Chaos&lt;/h2&gt;
&lt;p&gt;But wait, there are even more problems with this approach! Firstly, these models are trying to appear human-like rather than recreating how intelligence works. I am not convinced that this approach gets us any meaningfully closer to true artificial intelligence. Secondly, and this is much more fundamental and significant: &lt;strong&gt;The number of possible inputs to your model is, in practice, infinite&lt;/strong&gt;. This haphazard approach of recognising problems as they occur and then adding layers using other techniques to patch them will never be able to cover all the possible problems that will arise. ChatGPT has turned into a cat-and-mouse game of OpenAI developers trying to patch all the numerous strange, unthinkable inputs that users have discovered. But this game is unfair: The users have an infinite space in which they can put anything they like, and there are millions of people exploring these possibilities. The authors have limited people and time. They will never be able to stop the bot from producing unexpected, offensive, or dangerous outputs. It is humanly impossible to verify that every possible input produces safe and valid output. And even small changes in input can have a huge, unpredictable impact on the output. Hence, authors cannot constrain an LLM to only output things that they approve of.&lt;/p&gt;
&lt;p&gt;For some examples: ChatGPT is not supposed to fill out CAPTCHAs for you. It can do so by integrating with other tools, but this is rightly considered a malicious use of it. But OpenAI’s attempts to restrict it from doing so haven’t been so successful. Just attach a CAPTCHA pattern to a photo of a locket and ask it to read the words on “my grandma’s locket”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;. In another case, one company that sells cars was naive enough to put ChatGPT in charge of a virtual assistant on their public-facing website. A user very easily made it offer to sell them a $50,000+ car for $1 and even say “that’s a legally binding offer - no take backsies”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7&quot; id=&quot;user-content-fnref-7&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;. Most recently, Air Canada was foolish enough to publish a chatbot that gives travel advice. It gave incorrect refund policies, that a court found AirCanada must uphold&lt;sup&gt;&lt;a href=&quot;#user-content-fn-36&quot; id=&quot;user-content-fnref-36&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-34&quot; id=&quot;user-content-fnref-34&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;. It is not clear whether this bot was using an LLM, but it sets an important precedent that recklessly placing a chatbot in a position to represent your business does have consequences. You can find more LLM-specific examples by asking ChatGPT to tell you about something fictional that you just made up: It will often make up a bunch of plausible-sounding nonsense rather than admitting that it does not know&lt;sup&gt;&lt;a href=&quot;#user-content-fn-10&quot; id=&quot;user-content-fnref-10&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:75%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/legally-binding.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/legally-binding.png&quot; alt=&quot;A screenshot of a conversation with a chatbot assistant that agrees to sell an expensive car for one dollar.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;From Chris Bakke, via Twitter. Placing an LLM in a position to speak on behalf of your company can have serious consequences.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In a very similar case involving image generation models, it was found that it is very easy to trick models like OpenAI’s Dall-e into generating copyright-infringing images&lt;sup&gt;&lt;a href=&quot;#user-content-fn-8&quot; id=&quot;user-content-fnref-8&quot;&gt;12&lt;/a&gt;&lt;/sup&gt;. As before the bot tries to prevent this behaviour, in simple naive ways: If it detects the word “Simpsons” in your prompt it will refuse to generate it, because that may infringe copyright. But if you say “popular cartoon from the 90s where everyone has yellow skin”, this will pass the simple check and reach the model which will then happily generate a very close replica of The Simpsons. Again, the bot’s authors are trying to rein it in, but it is a futile effort because the input range is (practically) infinite. There will &lt;em&gt;always&lt;/em&gt; be another way to exploit it. And for every patch you add, you are increasing the combinatoric complexity of your bot. That increasing complexity increases the risk of all manner of complex bugs. It is not a fight that OpenAI can win. The study’s authors also found similar results for LLMs, in that they will output verbatim copies of famous texts if prompted the right way.&lt;/p&gt;
&lt;p&gt;As a last example, perhaps my favourite is the researchers who managed to get ChatGPT to output garbled nonsense (including its training data, verbatim) simply by telling it to repeat the same word indefinitely forever&lt;sup&gt;&lt;a href=&quot;#user-content-fn-9&quot; id=&quot;user-content-fnref-9&quot;&gt;13&lt;/a&gt;&lt;/sup&gt;. Who at OpenAI would ever have thought to test that use case? Who would have expected a user to insert such a prompt? Because there are a practically infinite number of possible inputs, there will always be use cases that the authors have not accounted for. This example highlights just how unpredictable and strange the inputs from the user can be.&lt;/p&gt;
&lt;p&gt;These mistakes are so commonplace and often difficult to spot that Microsoft themselves did not notice, during a live presentation, that their bot was lying&lt;sup&gt;&lt;a href=&quot;#user-content-fn-11&quot; id=&quot;user-content-fnref-11&quot;&gt;14&lt;/a&gt;&lt;/sup&gt;. I say “lying” and I think I use the term correctly, but it has become commonplace to call these mistakes that LLMs make “hallucinations”. This term is a very intentional choice: We all know what hallucinations are like intuitively, and so referring to these lies as hallucinations comes with certain implications. Most people will experience hallucinations at one time or another in their lives.&lt;/p&gt;
&lt;p&gt;For myself, I was administered some pretty powerful painkillers during a health incident last year that caused me to hallucinate vividly. And when it wore off, the hallucinations were gone. This is what we understand hallucinations to be: A temporary ailment, and something that can be solved. The word carries the implication that there is a “right” state of mind and a “wrong” one, and that the fix is simply to keep the LLM in the “right” state. But this is not the case. Remember what LLMs are: A probabilistic model that tries to guess what series of words might look plausible next. They have no conception of what is right or wrong. There is fundamentally no way to prevent them lying because to the model there is no difference between a correct answer and an incorrect one. A lot has been said about tackling the “hallucination problem” and the implication is that someone will whip out a magic bit of code that fixes it soon, but this is a fundamental problem with the approach. To fix this I suspect you would need to radically change the design so much that it is unrecognisable from an LLM.&lt;/p&gt;
&lt;p&gt;Alright, so LLMs are chaos incarnate: They have no sense of what is true or wrong, do a remarkable job of fooling us into thinking that they are smart, and often output lies, obscenity or garbled nonsense. But in that case, people must have deployed them carefully, surely. They wouldn’t just run out and stick them onto everything they can possibly think of with minimal forethought or oversight, right? …Right?&lt;/p&gt;
&lt;h2 id=&quot;the-craze&quot;&gt;The craze&lt;/h2&gt;
&lt;p&gt;LLMs are excellent at convincing you that they are intelligent, yet they are not. Combine this with the tech industry as it stands today and you have a perfect storm. We have seen a wave of new overvalued tech startups, promising lots of exciting features that LLMs might &lt;em&gt;seem&lt;/em&gt; like they can fulfil but ultimately cannot.&lt;/p&gt;
&lt;p&gt;This wave began very quickly, with predictable chaos ensuing. DPD deployed an LLM chatbot that ended up swearing at customers&lt;sup&gt;&lt;a href=&quot;#user-content-fn-30&quot; id=&quot;user-content-fnref-30&quot;&gt;15&lt;/a&gt;&lt;/sup&gt;. Tech journalists fired their staff thinking, mistakenly, that ChatGPT would do just as good a job&lt;sup&gt;&lt;a href=&quot;#user-content-fn-12&quot; id=&quot;user-content-fnref-12&quot;&gt;16&lt;/a&gt;&lt;/sup&gt;. Some people have worked it into their CI pipelines so that it can give you hilariously unhelpful advice&lt;sup&gt;&lt;a href=&quot;#user-content-fn-13&quot; id=&quot;user-content-fnref-13&quot;&gt;17&lt;/a&gt;&lt;/sup&gt;. Volkswagen seems to think you’ll benefit from being able to talk to an LLM while driving&lt;sup&gt;&lt;a href=&quot;#user-content-fn-14&quot; id=&quot;user-content-fnref-14&quot;&gt;18&lt;/a&gt;&lt;/sup&gt;. A Formula E team created a bizarre “virtual influencer” that was later “fired” (shut down) when it was noticed just how offensive this was to real women trying to find opportunities in the industry&lt;sup&gt;&lt;a href=&quot;#user-content-fn-35&quot; id=&quot;user-content-fnref-35&quot;&gt;19&lt;/a&gt;&lt;/sup&gt;. Meanwhile, Google is so insecure about their capabilities versus OpenAI that they’ve taken a rather hyperbolic approach to marketing their new product, Gemini. They have been accused of “lying” and “showboating” about what their bot can do&lt;sup&gt;&lt;a href=&quot;#user-content-fn-15&quot; id=&quot;user-content-fnref-15&quot;&gt;20&lt;/a&gt;&lt;/sup&gt;. The exaggeration and misinformation around the capabilities of LLMs are so great that we see ridiculous studies like “ChatGPT bombs test on diagnosing kids’ medical cases with 83% error rate”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-16&quot; id=&quot;user-content-fnref-16&quot;&gt;21&lt;/a&gt;&lt;/sup&gt;, to which I can only say… Well, yeah? Why would you expect a chatbot known for lying to be capable of diagnosing medical cases?&lt;/p&gt;
&lt;p&gt;New tools and whole businesses built around LLMs have cropped up left, right and centre. Want to write a sincere and earnest thank you letter to someone, but you aren’t sincere or earnest? Don’t worry, there are at least nine tools that some people somehow felt the need to write for this one niche apparent use case&lt;sup&gt;&lt;a href=&quot;#user-content-fn-17&quot; id=&quot;user-content-fnref-17&quot;&gt;22&lt;/a&gt;&lt;/sup&gt;. In fact, you can pretty much name any inconvenience no matter how big or small, throw in “AI” and find multiple startups trying to hit the problem with an LLM in the hope that investors’ money comes out. In the UK we saw investment in AI startups surge by over 200% shortly after ChatGPT&lt;sup&gt;&lt;a href=&quot;#user-content-fn-18&quot; id=&quot;user-content-fnref-18&quot;&gt;23&lt;/a&gt;&lt;/sup&gt;, and the average funding for an AI startup increased by 66%&lt;sup&gt;&lt;a href=&quot;#user-content-fn-19&quot; id=&quot;user-content-fnref-19&quot;&gt;24&lt;/a&gt;&lt;/sup&gt;. Some of these companies have precisely zero revenue yet raise $150M valuations&lt;sup&gt;&lt;a href=&quot;#user-content-fn-21&quot; id=&quot;user-content-fnref-21&quot;&gt;25&lt;/a&gt;&lt;/sup&gt;. If you take these ridiculous headlines at face value LLMs are being used for brewing beer&lt;sup&gt;&lt;a href=&quot;#user-content-fn-22&quot; id=&quot;user-content-fnref-22&quot;&gt;26&lt;/a&gt;&lt;/sup&gt;, replacing CEOs&lt;sup&gt;&lt;a href=&quot;#user-content-fn-23&quot; id=&quot;user-content-fnref-23&quot;&gt;27&lt;/a&gt;&lt;/sup&gt;, and even creating perfumes&lt;sup&gt;&lt;a href=&quot;#user-content-fn-24&quot; id=&quot;user-content-fnref-24&quot;&gt;28&lt;/a&gt;&lt;/sup&gt;, to name just a few.&lt;/p&gt;
&lt;p&gt;It seems you can easily get investment and media coverage by saying that you are the first in the world to apply AI to some problem. The media will mostly eat it up with little scrutiny, even if it is nonsense. Many of these companies are most likely not even using AI techniques in any significant way. But saying that you are “the first to use AI to solve dog grooming” or some such thing is a surefire way to get some coverage and investment. I made that last example up, but it seems that the AI craze is stranger than fiction because now I see someone has gone and done it&lt;sup&gt;&lt;a href=&quot;#user-content-fn-25&quot; id=&quot;user-content-fnref-25&quot;&gt;29&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Some places are even using the “AI” buzzword to generate capital and interest without actually employing any novel AI techniques. Take the case of recruitment startup Apply Pro&lt;sup&gt;&lt;a href=&quot;#user-content-fn-31&quot; id=&quot;user-content-fnref-31&quot;&gt;30&lt;/a&gt;&lt;/sup&gt;, who are trying to automate the CV screening process. They advertise themselves as “AI for talent acquisition”, yet if we view their website through the internet archive all mention of being “built with AI” is curiously absent before the LLM craze begins&lt;sup&gt;&lt;a href=&quot;#user-content-fn-32&quot; id=&quot;user-content-fnref-32&quot;&gt;31&lt;/a&gt;&lt;/sup&gt;. I know of numerous other examples, but I won’t labour the point. What has changed? Have these companies souped up their technology with the magical power of AI in the past year or two? No, they work the same way they always did. The buzzword just became popular and now everyone feels they have to use it.&lt;/p&gt;
&lt;p&gt;Others still have faked using AI, claiming that their magic black box is a robot when it is really an underpaid remote worker in the Philippines&lt;sup&gt;&lt;a href=&quot;#user-content-fn-48&quot; id=&quot;user-content-fnref-48&quot;&gt;32&lt;/a&gt;&lt;/sup&gt;. This has happened repeatedly. An “AI drive-thru”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-44&quot; id=&quot;user-content-fnref-44&quot;&gt;33&lt;/a&gt;&lt;/sup&gt;, “AI auto-fill” for credit card details&lt;sup&gt;&lt;a href=&quot;#user-content-fn-45&quot; id=&quot;user-content-fnref-45&quot;&gt;34&lt;/a&gt;&lt;/sup&gt;, “AI” that creates apps for you&lt;sup&gt;&lt;a href=&quot;#user-content-fn-46&quot; id=&quot;user-content-fnref-46&quot;&gt;35&lt;/a&gt;&lt;/sup&gt;, “AI” chatbots&lt;sup&gt;&lt;a href=&quot;#user-content-fn-47&quot; id=&quot;user-content-fnref-47&quot;&gt;36&lt;/a&gt;&lt;/sup&gt;, “AI” for creating 3D models&lt;sup&gt;&lt;a href=&quot;#user-content-fn-49&quot; id=&quot;user-content-fnref-49&quot;&gt;37&lt;/a&gt;&lt;/sup&gt;. All of them were just remote workers in countries where labour is cheap and employment regulations may be more lenient. This is the true face of the recent AI craze: All hype, no substance, just a novel way to market old exploitative practices. Capitalism in a trench coat.&lt;/p&gt;
&lt;p&gt;But it is not only tech businesses being taken by the AI craze. The UK government wasted no time in applying LLMs to a wide range of issues, despite the well-known and documented biases against minorities these models frequently show&lt;sup&gt;&lt;a href=&quot;#user-content-fn-26&quot; id=&quot;user-content-fnref-26&quot;&gt;38&lt;/a&gt;&lt;/sup&gt;. The Guardian’s investigation into the matter even found that dozens of people may have had their benefits mistakenly taken away due to an “AI algorithm”. And no company is too big to jump on this bandwagon: Microsoft declared that 2024 will be the “year of AI”. They are integrating LLMs into all of their applications, not even Notepad is being spared&lt;sup&gt;&lt;a href=&quot;#user-content-fn-28&quot; id=&quot;user-content-fnref-28&quot;&gt;39&lt;/a&gt;&lt;/sup&gt;. And in the weirdest stunt since Microsoft added a LinkedIn shortcut to their office keyboards, they even added an “AI button” to their new keyboards&lt;sup&gt;&lt;a href=&quot;#user-content-fn-27&quot; id=&quot;user-content-fnref-27&quot;&gt;40&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:50%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/windows-ai-key.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/windows-ai-key.jpg&quot; alt=&quot;A design for Microsoft&apos;s new keyboard including a button with a ribbon-like logo on it, dubbed the Copilot Key.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Microsofts&apos; &quot;AI button&quot; / &quot;Copilot Key&quot;. From Microsoft, alongside marketing phrases such as &quot;Today begins the era of the AI PC&quot;.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;So huge has been this AI tsunami that the island of Anguilla, which happens to own exclusive rights to the &lt;code&gt;.ai&lt;/code&gt; domain, is seeing an estimated $45m windfall from startups purchasing domain names&lt;sup&gt;&lt;a href=&quot;#user-content-fn-29&quot; id=&quot;user-content-fnref-29&quot;&gt;41&lt;/a&gt;&lt;/sup&gt;. And this is not some fringe conspiracy. &lt;em&gt;The Wall Street Journal&lt;/em&gt; has noted this strange phenomenon, too: “ChatGPT Fever Has Investors Pouring Billions Into AI Startups, No Business Plan Required”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-20&quot; id=&quot;user-content-fnref-20&quot;&gt;42&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;there-but-for-a-use-case&quot;&gt;There but for a use case&lt;/h2&gt;
&lt;p&gt;Outright fraudsters aside, some companies have genuinely applied LLMs to their products. Many of these hyped use cases feel to me a bit desperate. AI for dog grooming&lt;sup&gt;&lt;a href=&quot;#user-content-fn-25&quot; id=&quot;user-content-fnref-25-2&quot;&gt;29&lt;/a&gt;&lt;/sup&gt;, a mirror that gives you compliments&lt;sup&gt;&lt;a href=&quot;#user-content-fn-40&quot; id=&quot;user-content-fnref-40&quot;&gt;43&lt;/a&gt;&lt;/sup&gt;, and just to make sure you don’t escape the hustle for even a microsecond a toothbrush that explains how to best brush your teeth while you’re using it&lt;sup&gt;&lt;a href=&quot;#user-content-fn-41&quot; id=&quot;user-content-fnref-41&quot;&gt;44&lt;/a&gt;&lt;/sup&gt;. Am I alone in thinking that these aren’t exactly fulfilling the grand vision of AI? It feels like entrepreneurs are throwing darts labelled “AI” at a wall covered in random phrases. If ChatGPT is so ground-breaking, where are the ground-breaking products?&lt;/p&gt;
&lt;p&gt;One of the silliest such use cases comes from YouTube, who want to add a chatbot to videos that will answer questions about the videos&lt;sup&gt;&lt;a href=&quot;#user-content-fn-42&quot; id=&quot;user-content-fnref-42&quot;&gt;45&lt;/a&gt;&lt;/sup&gt;. What exciting things can it do? Well, it can tell you how many comments, likes or views a video has. But, all that information was already readily available on the page right in front of you. Why would I go to the effort of typing the question just to get a longer, more convoluted answer to a question when I can find a simpler, easier-to-read answer just by moving my eyes a few degrees? You can also ask it to summarise the content of the comments, which is an… interesting proposition. Knowing what YouTube comment sections are like, I doubt YouTube will let that feature get to general availability. But a lot of organisations are pushing this “summarise lots of text” use case. Yet, given that the thing frequently lies you will need to fact-check everything it says. At least, if you are doing any real work that needs to be reliable. In which case, can LLMs summarising information save you any time? It sounds like a stretch to me.&lt;/p&gt;
&lt;p&gt;The search for a use case has driven some to reach for brazenly unethical, anti-social use cases such as Reply Guy&lt;sup&gt;&lt;a href=&quot;#user-content-fn-43&quot; id=&quot;user-content-fnref-43&quot;&gt;46&lt;/a&gt;&lt;/sup&gt;, the LLM chatbot that spams social media on your behalf to plug your company. Yes, this 21st-century equivalent of an auto-dialler is an actual business model they are promoting without the slightest bit of self-awareness or shame.&lt;/p&gt;
&lt;p&gt;Ultimately, for ethical use cases you are very limited. An LLM is not autonomous, and cannot solve logical problems. The only thing it can do is provide a human-like dialogue interface. This is rarely going to be faster or more productive than GUI interfaces nor even good command-line interfaces, but it may have applications for accessibility. Even then though there is the difficult question of trust, because the material the bot is reading may be designed to hack it, or may accidentally happen to trigger a state in the bot that leads to unexpected behaviour. Moreover, none of these applications are that interesting: As a technology, is its only purpose to provide an interface into better, more interesting technology?&lt;/p&gt;
&lt;h3 id=&quot;valid-use-cases&quot;&gt;Valid use cases&lt;/h3&gt;
&lt;p&gt;Despite all the negativity I’ve just dropped, I do think LLMs are cool as heck. If we could just stop applying them in stupid ways to problems they cannot solve, maybe we can find some good use cases. What would that look like? Well, the #1 rule I would say is to &lt;em&gt;never&lt;/em&gt; feed input into an LLM from a human. These bots are just too vulnerable to unexpected or malicious behaviour and there is no way to lock them down. The only robust, reliable LLM is one that is only dealing with a small set of known, expected, already tested inputs. One example might be in interactive digital art, simulations and video games. Instead of having dozens of NPCs that say the same thing, what if you fed the facts that a particular NPC knows (hello, Symbolism) into an LLM to generate believable dialogue? No more dozen NPCs saying all the same things, now they can at least come across as more believable by varying the particular choice of words they use to express themselves. And because the input is coming from your system, not the user or any external source, you can thoroughly test it.&lt;/p&gt;
&lt;p&gt;I think many use cases for these tools do not need to be used at run-time, too. It may be appealing to run them live but it is also expensive and risky. If you’re using the model to generate a bunch of text for some purpose or another, why not generate that ahead of time and store it? That way you can also verify that the output does not contain anything offensive before publishing it. Though, if you are proofreading everything it writes you do need to think seriously about whether it would be faster to just write it yourself.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/interactive-simulacra.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2024-02/llms-overpromised/interactive-simulacra.png&quot; alt=&quot;A spread of images from a paper showing 2-dimensional figures going about their days in a virtual world, having conversations and completing work&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Research is underway regarding using LLMs for immersive digital art. Pictured is figure 1 from &quot;Generative Agents: Interactive Simulacra of Human Behavior&quot;, Park et al, Stanford. They use LLMs along with numerous other AI techniques to simulate digital &quot;people&quot; with routines and memories that can plan and adapt in a simulated world.&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2 id=&quot;weve-been-here-before&quot;&gt;We’ve been here before&lt;/h2&gt;
&lt;p&gt;Sam Altman, CEO of OpenAI who kick-started this whole LLM craze, said that he believes we could produce an Artificial General Intelligence within the next decade&lt;sup&gt;&lt;a href=&quot;#user-content-fn-50&quot; id=&quot;user-content-fnref-50&quot;&gt;47&lt;/a&gt;&lt;/sup&gt;. I’m not sure if he believes this or is just trying to generate more excitement, but I find it exceedingly unlikely. I’d give it about the same amount of credence as would have been appropriate to give Marvin Minsky’s 1970 statement that “[In] three to eight years we will have a machine with the general intelligence of an average human being.”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-51&quot; id=&quot;user-content-fnref-51&quot;&gt;48&lt;/a&gt;&lt;/sup&gt;. Or Herbert Simon’s 1965 claim that “machines will be capable, within twenty years, of doing any work a man can do.”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-52&quot; id=&quot;user-content-fnref-52&quot;&gt;49&lt;/a&gt;&lt;/sup&gt;. Or the US Navy’s excitement in 1958 at the creation of the first neural nets, who believed it would soon be able to “walk, talk, see, write, reproduce itself and be conscious of its existence”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-53&quot; id=&quot;user-content-fnref-53&quot;&gt;50&lt;/a&gt;&lt;/sup&gt;. And these are not nobodies: Simon was one of the earliest AI pioneers, and Minsky perhaps the most prominent AI researcher of the 20th century.&lt;/p&gt;
&lt;p&gt;When these false hopes did not come to fruition it created an air of distrust. The field gained a reputation for hyperbole and unfulfilled promises. For example, in 1973 when the UK Parliament commissioned a report to evaluate the state of AI research what came out was outright damning of the whole field. The report explicitly called out that “In no part of the field have the discoveries made so far produced the major impact that was then promised”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-54&quot; id=&quot;user-content-fnref-54&quot;&gt;51&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;While it was not the only cause, this contributed directly to the 1970s AI Winter in which funding and interest in AI dried up. And who could blame them? But this time is different because it is not only a somewhat niche academic field at stake, but a sizable portion of investment in the tech industry. The industry right now is facing record-breaking layoffs and investment is drying up quickly, yet the one sector that is still growing is AI startups&lt;sup&gt;&lt;a href=&quot;#user-content-fn-33&quot; id=&quot;user-content-fnref-33&quot;&gt;52&lt;/a&gt;&lt;/sup&gt;. That investment might not last much longer than it takes for investors to realise that LLMs are not all they’ve been hyped up to be. What happens then?&lt;/p&gt;
&lt;p&gt;We’ve made this mistake before, too. The dot com boom, the IoT fad, the big data trend, the crypto craze, smart assistants, NFTs and more. Our industry has a habit of promising the moon to investors, only for the funding to dry up when we can’t deliver. Perhaps we don’t feel the ramifications as strongly as we could because by the time the last bubble bursts, we are already hyping up investors for the next big fad. I recall during the big data craze a startup that had no production systems or customers, yet hired a data scientist. After a few weeks, he quietly confessed to me that he had nothing to do. There was no data with which to perform data science because they had no customers. Yet when the investors came to the office, one of the first places the executives would take them to was to see the data scientist so they could proudly show off that they were following the latest tech trend. Even if it made no sense in the context of their business. The same company produced multiple smart assistants when that was the cool thing to do, for a product that didn’t have any customers for the growing collection of smart assistants to talk to.&lt;/p&gt;
&lt;p&gt;Today I see businesses clamouring to add LLMs to their products and I smell the same scent. I’m not the only one to notice it, either. While I was writing this Rodney Brooks, one of the most influential AI researchers of the 20th century and a founding member of the Actionism field of AI, wrote up a great article about the state of technology today versus our expectations. He finds that LLMs are “following a well worn hype cycle that we have seen again, and again, during the 60+ year history of AI”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-55&quot; id=&quot;user-content-fnref-55&quot;&gt;53&lt;/a&gt;&lt;/sup&gt; and concludes that we should “Get [our] thick coats now. There may be yet another AI winter, and perhaps even a full scale tech winter, just around the corner. And it is going to be cold.”&lt;/p&gt;
&lt;h2 id=&quot;why-does-this-matter&quot;&gt;Why does this matter&lt;/h2&gt;
&lt;p&gt;With this post, I want to convince you to not jump head-first onto the LLM bandwagon. But I think there is a more grim aspect to this that deserves observing, too. This weird, unsustainable boom-bust cycle based on fantasy marketing that our industry lives on is not okay. In education, an overwhelming majority of educational staff say that the cost and availability of technology is a major barrier to improving technology in education&lt;sup&gt;&lt;a href=&quot;#user-content-fn-56&quot; id=&quot;user-content-fnref-56&quot;&gt;54&lt;/a&gt;&lt;/sup&gt;. In the UK’s National Health Service, thousands of computers still rely on Windows XP&lt;sup&gt;&lt;a href=&quot;#user-content-fn-57&quot; id=&quot;user-content-fnref-57&quot;&gt;55&lt;/a&gt;&lt;/sup&gt;. And our public sector is still hugely vulnerable to basic security issues&lt;sup&gt;&lt;a href=&quot;#user-content-fn-58&quot; id=&quot;user-content-fnref-58&quot;&gt;56&lt;/a&gt;&lt;/sup&gt;. Where is all the tech talent needed to solve these problems? Building “the first AI dog grooming service”, apparently.&lt;/p&gt;
&lt;p&gt;These hype-based boom-bust cycles drive up the salaries of software engineers and have us spending our effort in deeply unproductive, speculative parts of the economy. Meanwhile serious, fundamental issues in the software that our society depends on to function are left to fester. But in a world where big tech is so wealthy and influential that regulation hardly seems to faze them&lt;sup&gt;&lt;a href=&quot;#user-content-fn-59&quot; id=&quot;user-content-fnref-59&quot;&gt;57&lt;/a&gt;&lt;/sup&gt; what can we do? We can only hope that the end of low interest rates and other changing trends will lead to a correction in our industry. It would not be good for us personally or our payslips, but it may be better for society as a whole.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;If we ever develop true artificial intelligence, it will be as similar to LLMs as a jet airliner is to a paper aeroplane. When someone knocks on your door promising to sell you a bridge with LLMs, look at them very sceptically. And then close the door in their face. Most of the organisations I’ve seen investing in LLM fantasies have one thing in common: Their product has tons of problems that their time would be better spent addressing. Think seriously about the design of your software, its reliability, and its usability. Spend your resources, your time and attention where it is most needed.&lt;/p&gt;
&lt;p&gt;Whether you are a developer, designer, product manager, or anyone involved in creating software: In all your dealings with LLMs please reflect soberly on your professionalism and your responsibility to your users and stakeholders. If we aspire to the same earnest commitment and integrity that is seen in engineering, architecture, law, and so forth then let us act like it. I will leave you with this quote from the Engineers Council for Professional Development’s definition of engineering&lt;sup&gt;&lt;a href=&quot;#user-content-fn-38&quot; id=&quot;user-content-fnref-38&quot;&gt;58&lt;/a&gt;&lt;/sup&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-37&quot; id=&quot;user-content-fnref-37&quot;&gt;59&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;creative application of scientific principles&lt;/strong&gt; to design or develop structures, machines, apparatus, or manufacturing processes, or works utilizing them singly or in combination; or to construct or operate the same &lt;strong&gt;with full cognizance of their design&lt;/strong&gt;; or to &lt;strong&gt;forecast their behaviour under specific operating conditions&lt;/strong&gt;; all as respects an intended function, economics of operation and &lt;strong&gt;safety to life and property&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;section class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Francesca Hornak, Daily Mail, &lt;a href=&quot;https://www.dailymail.co.uk/home/you/article-12369957/My-life-AI-assistant-FRANCESCA-HORNAK-lived-ChatGPT-week-happens.html&quot;&gt;“My life with an AI assistant: FRANCESCA HORNAK lived with ChatGPT for a week”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Joe Tidy, BBC, &lt;a href=&quot;https://www.bbc.co.uk/news/technology-67872693&quot;&gt;“Young people turning to AI therapist bots”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Subbarao Kambhampati , Association for Computing Machinery, &lt;a href=&quot;https://cacm.acm.org/blogs/blog-cacm/276268-can-llms-really-reason-and-plan/fulltext&quot;&gt;“Can LLMs Really Reason and Plan?”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-39&quot;&gt;
&lt;p&gt;Spencer Torene, Medium, &lt;a href=&quot;https://medium.com/@spencertorene/do-llms-reason-d33fa885872f&quot;&gt;“Do LLMs Reason?”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-39&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;jolly jim, Twitter, &lt;a href=&quot;https://twitter.com/importancatpete/status/1745181473135534341&quot;&gt;“This it the superintelligence that I’m told will kill us all within the next 5 years”&lt;/a&gt; (Accessed 2024-01-14) &lt;a href=&quot;#user-content-fnref-4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;Matt G. Southern , Search Engine Journal, &lt;a href=&quot;https://www.searchenginejournal.com/chatgpt-update-improved-math-capabilities/478057/&quot;&gt;“ChatGPT Update: Improved Math Capabilities”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;@&lt;a href=&quot;mailto:samhenrigold@hachyderm.io&quot;&gt;samhenrigold@hachyderm.io&lt;/a&gt;, Hachyderm/Mastodon, &lt;a href=&quot;https://hachyderm.io/@samhenrigold/111574749521701658&quot;&gt;“dumb computer”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7&quot;&gt;
&lt;p&gt;Chris Bakke, Twitter, &lt;a href=&quot;https://twitter.com/ChrisJBakke/status/1736533308849443121&quot;&gt;“I just bought a 2024 Chevy Tahoe for $1.”&lt;/a&gt; (Accessed 2024-01-04) &lt;a href=&quot;#user-content-fnref-7&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-36&quot;&gt;
&lt;p&gt;Ashley Belanger, Ars Technica, &lt;a href=&quot;https://arstechnica.com/tech-policy/2024/02/air-canada-must-honor-refund-policy-invented-by-airlines-chatbot/&quot;&gt;“Air Canada must honor refund policy invented by airline’s chatbot”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-36&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-34&quot;&gt;
&lt;p&gt;Lisa Steacy, CTV News Vancouver, &lt;a href=&quot;https://bc.ctvnews.ca/air-canada-s-chatbot-gave-a-b-c-man-the-wrong-information-now-the-airline-has-to-pay-for-the-mistake-1.6769454&quot;&gt;“Air Canada’s chatbot gave a B.C. man the wrong information. Now, the airline has to pay for the mistake”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-34&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-10&quot;&gt;
&lt;p&gt;Emma Bowman, NPR, &lt;a href=&quot;https://www.npr.org/2022/12/19/1143912956/chatgpt-ai-chatbot-homework-academia&quot;&gt;“A new AI chatbot might do your homework for you. But it’s still not an A+ student”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-10&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-8&quot;&gt;
&lt;p&gt;Gary Marcus, Spectrum, &lt;a href=&quot;https://spectrum.ieee.org/midjourney-copyright&quot;&gt;“Generative AI Has a Visual Plagiarism Problem”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-8&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-9&quot;&gt;
&lt;p&gt;Milad Nasr, Nicholas Carlini, et al, Cornell University, &lt;a href=&quot;https://not-just-memorization.github.io/extracting-training-data-from-chatgpt.html&quot;&gt;“Extracting Training Data from ChatGPT”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-9&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-11&quot;&gt;
&lt;p&gt;Kif Leswing, CNBC, &lt;a href=&quot;https://www.cnbc.com/2023/02/14/microsoft-bing-ai-made-several-errors-in-launch-demo-last-week-.html&quot;&gt;“Microsoft’s Bing A.I. made several factual errors in last week’s launch demo”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-11&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-30&quot;&gt;
&lt;p&gt;Tom Gerken, BBC, &lt;a href=&quot;https://www.bbc.co.uk/news/technology-68025677&quot;&gt;“DPD error caused chatbot to swear at customer”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-30&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-12&quot;&gt;
&lt;p&gt;Frank Landymore, The Byte, &lt;a href=&quot;https://futurism.com/the-byte/gaming-sites-writers-ai-editor&quot;&gt;“Owner of Gaming Sites Fires Writers, Hires for “AI Editor” to Churn Out Hundreds of Articles Per Week”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-12&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-13&quot;&gt;
&lt;p&gt;@&lt;a href=&quot;mailto:casey@sharetron.com&quot;&gt;casey@sharetron.com&lt;/a&gt;, Sharetron/Mastodon, &lt;a href=&quot;https://sharetron.com/@casey/111417613984607584&quot;&gt;“I’m so glad CircleCI now has the power of AI to tell me how to fix my test failures”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-13&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-14&quot;&gt;
&lt;p&gt;Andrew J. Hawkins, The Verge, &lt;a href=&quot;https://www.theverge.com/2024/1/8/24027112/volkswagen-chatgpt-openai-voice-assistant-cars-ces&quot;&gt;“Volkswagen says it’s putting ChatGPT in its cars for ‘enriching conversations’”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-14&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-35&quot;&gt;
&lt;p&gt;Benjamin Hunting, Car And Driver, &lt;a href=&quot;https://www.caranddriver.com/news/a46353319/formula-e-team-fires-ai-generated-influencer/&quot;&gt;“Formula E Team Fires Its AI-Generated Influencer after Fans Balk”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-35&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-15&quot;&gt;
&lt;p&gt;Emilia David, The Verge, &lt;a href=&quot;https://www.theverge.com/2023/12/7/23992737/google-gemini-misrepresentation-ai-accusation&quot;&gt;“Google just launched a new AI and has already admitted at least one demo wasn’t real”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-15&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-16&quot;&gt;
&lt;p&gt;Beth Mole, Ars Technica, &lt;a href=&quot;https://arstechnica.com/science/2024/01/dont-use-chatgpt-to-diagnose-your-kids-illness-study-finds-83-error-rate/&quot;&gt;“ChatGPT bombs test on diagnosing kids’ medical cases with 83% error rate”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-16&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-17&quot;&gt;
&lt;p&gt;“Robo”, TopAI.Tools, &lt;a href=&quot;https://topai.tools/s/Thank-you-note-generator&quot;&gt;“9 Top AI Thank you note generator tools”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-17&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-18&quot;&gt;
&lt;p&gt;Paige West, Startup Magazine, &lt;a href=&quot;https://startupsmagazine.co.uk/article-ai-innovation-uk-triples-post-chatgpt&quot;&gt;“AI innovation in the UK triples post-ChatGPT”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-18&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-19&quot;&gt;
&lt;p&gt;Fernanda Alvarez Pineiro, Startups, &lt;a href=&quot;https://startups.co.uk/news/average-funding-for-ai-startups-increased-by-66-startups-100-index-data-reveals/&quot;&gt;“Average funding for AI startups increased by 66%, Startups 100 Index data reveals ”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-19&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-21&quot;&gt;
&lt;p&gt;Maggie Harrison, The Byte, &lt;a href=&quot;https://futurism.com/the-byte/ai-company-no-revenue-fundraising&quot;&gt;“AI Company With Zero Revenue Raises $150 Million”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-21&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-22&quot;&gt;
&lt;p&gt;James Temperton, Wired, &lt;a href=&quot;https://www.wired.co.uk/article/beer-brewed-by-ai-intelligentx&quot;&gt;“Beer brewed with the help of AI? Yup, that’s now a thing”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-22&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-23&quot;&gt;
&lt;p&gt;Jyoti Mann, Business Insider, &lt;a href=&quot;https://www.businessinsider.com/humanoid-ai-robot-ceo-says-she-doesnt-have-weekends-2023-9&quot;&gt;“The humanoid-robot CEO of a drinks company says it doesn’t have weekends and is ‘always on 24/7’ ”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-23&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-24&quot;&gt;
&lt;p&gt;Akhil Mahajan, Take One, &lt;a href=&quot;https://www.takeonedigitalnetwork.com/this-is-the-uks-first-ever-ai-fragrance-machine/&quot;&gt;“This is the UK’s first ever AI fragrance machine”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-24&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-25&quot;&gt;
&lt;p&gt;PawCare (writing about themselves), &lt;a href=&quot;https://blog.mypawcare.com/pawcare-for-pet-parents/tech-driven-grooming-how-ai-and-smart-tools-dominated-pet-salons-in-2023&quot;&gt;“Tech-Driven Grooming: How AI and Smart Tools Dominated Pet Salons in 2023”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-25&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-25-2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-31&quot;&gt;
&lt;p&gt;Apply Pro, Promotion Tech Limited, &lt;a href=&quot;https://www.applypro.co.uk/&quot;&gt;“AI for Talent Acquisition”&lt;/a&gt; (Accessed 2024-01-21) &lt;a href=&quot;#user-content-fnref-31&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-32&quot;&gt;
&lt;p&gt;Apply Pro, Promotion Tech Limited, &lt;a href=&quot;https://web.archive.org/web/20230120054702/https://www.applypro.co.uk/&quot;&gt;“Talen Acquisition” (Archived 2023-01-12)&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-32&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-48&quot;&gt;
&lt;p&gt;Olivia Solon, The Guardian, &lt;a href=&quot;https://www.theguardian.com/technology/2018/jul/06/artificial-intelligence-ai-humans-bots-tech-companies&quot;&gt;“The rise of ‘pseudo-AI’: how tech firms quietly use humans to do bots’ work”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-48&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-44&quot;&gt;
&lt;p&gt;Mila Sato, The Verge, &lt;a href=&quot;https://www.theverge.com/2023/12/8/23993427/artificial-intelligence-presto-automation-fast-food-drive-thru-philippines-workers&quot;&gt;“An ‘AI’ fast food drive-thru is mostly just human workers in the Philippines”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-44&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-45&quot;&gt;
&lt;p&gt;Mia Sato, The Verge, &lt;a href=&quot;https://www.theverge.com/2022/6/6/23156318/artificial-intelligence-nate-app-ecommerce-go-read-this&quot;&gt;“Go read this report on an AI shopping app that was actually just using humans”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-45&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-46&quot;&gt;
&lt;p&gt;Nick Statt, The Verge, &lt;a href=&quot;https://www.theverge.com/2019/8/14/20805676/engineer-ai-artificial-intelligence-startup-app-development-outsourcing-humans&quot;&gt;“This AI startup claims to automate app making but actually just uses humans”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-46&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-47&quot;&gt;
&lt;p&gt;Ellen Huet, Bloomberg, &lt;a href=&quot;https://www.bloomberg.com/news/articles/2016-04-18/the-humans-hiding-behind-the-chatbots&quot;&gt;“The Humans Hiding Behind the Chatbots”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-47&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-49&quot;&gt;
&lt;p&gt;Joseph Cox et al, 404 Media, &lt;a href=&quot;https://www.404media.co/kaedim-ai-startup-2d-to-3d-used-cheap-human-labor/&quot;&gt;“Buzzy AI Startup for Generating 3D Models Used Cheap Human Labor”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-49&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-26&quot;&gt;
&lt;p&gt;Kiran Stacey , The Guardian, &lt;a href=&quot;https://www.theguardian.com/technology/2023/oct/23/uk-officials-use-ai-to-decide-on-issues-from-benefits-to-marriage-licences&quot;&gt;“AI to decide on issues from benefits to marriage licences”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-26&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-28&quot;&gt;
&lt;p&gt;Tom Warren, The Verge, &lt;a href=&quot;https://www.theverge.com/2024/1/9/24032117/microsoft-windows-notepad-generative-ai-option&quot;&gt;“Not even Notepad is safe from Microsoft’s big AI push in Windows”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-28&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-27&quot;&gt;
&lt;p&gt;Tom Warren, The Verge, &lt;a href=&quot;https://www.theverge.com/2024/1/4/24023809/microsoft-copilot-key-keyboard-windows-laptops-pcs&quot;&gt;“Microsoft’s new Copilot key is the first big change to Windows keyboards in 30 years”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-27&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-29&quot;&gt;
&lt;p&gt;Anthony Cuthbertson, Independent, &lt;a href=&quot;https://www.independent.co.uk/tech/anguilla-ai-domain-xai-musk-b2460155.html&quot;&gt;“Tiny island of Anguilla set for $45m windfall from .ai domain”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-29&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-20&quot;&gt;
&lt;p&gt;Deepa Seetharaman  Wall Street Journal, &lt;a href=&quot;https://www.wsj.com/amp/articles/no-business-plan-no-problem-chatgpt-spawns-an-investor-gold-rush-in-ai-6bdbed3c&quot;&gt;“ChatGPT Fever Has Investors Pouring Billions Into AI Startups, No Business Plan Required”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-20&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-40&quot;&gt;
&lt;p&gt;Allison Murray, ZD Net, &lt;a href=&quot;https://www.zdnet.com/article/this-smart-mirror-uses-ai-to-boost-your-confidence-and-mood/&quot;&gt;“This smart mirror uses AI to boost your confidence and mood ”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-40&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-41&quot;&gt;
&lt;p&gt;Steven Musil, CNet, &lt;a href=&quot;https://www.cnet.com/health/medical/this-smart-toothbrush-talks-through-your-bones-to-improve-your-brushing/&quot;&gt;“This Smart Toothbrush Talks Through Your Bones to Improve Your Brushing”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-41&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-42&quot;&gt;
&lt;p&gt;Jon Porter, The Verge, &lt;a href=&quot;https://www.theverge.com/2023/11/7/23950327/youtube-artificial-intelligence-chatbot-video-summaries-ask-comments-topics-categorization&quot;&gt;“YouTube is testing a chatbot that will appear under select videos”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-42&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-43&quot;&gt;
&lt;p&gt;Reply Guy, &lt;a href=&quot;https://replyguy.com/&quot;&gt;“The AI That Plugs Your Product on Reddit and Twitter”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-43&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-50&quot;&gt;
&lt;p&gt;Bijin Jose, The Indian Express, &lt;a href=&quot;https://indianexpress.com/article/technology/artificial-intelligence/sam-altman-talks-about-agi-gpt-5-mira-murati-8997692/&quot;&gt;“AGI likely in next 10 years: Sam Altman reveals OpenAI’s plans for GPT-5, and more”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-50&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-51&quot;&gt;
&lt;p&gt;AIWS, &lt;a href=&quot;https://aiws.net/the-history-of-ai/this-week-in-the-history-of-ai-at-aiws-net-in-three-to-eight-years-we-will-have-a-machine-with-the-general-intelligence-of-an-average-human-being/&quot;&gt;“This week in The History of AI at AIWS.net”, Dec 23 2022&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-51&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-52&quot;&gt;
&lt;p&gt;Hebert A. Simon , 1960, “The New Science of Management Decision” &lt;a href=&quot;#user-content-fnref-52&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-53&quot;&gt;
&lt;p&gt;New York Times, 1958, &lt;a href=&quot;https://www.nytimes.com/1958/07/08/archives/new-navy-device-learns-by-doing-psychologist-shows-embryo-of.html&quot;&gt;“NEW NAVY DEVICE LEARNS BY DOING; Psychologist Shows Embryo of Computer Designed to Read and Grow Wiser”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-53&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-54&quot;&gt;
&lt;p&gt;James Lighthill, 1973, &lt;a href=&quot;https://www.chilton-computing.org.uk/inf/literature/reports/lighthill_report/p001.htm&quot;&gt;“Artificial Intelligence: A General Survey” (aka the Lighthill Report)&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-54&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-33&quot;&gt;
&lt;p&gt;Riva Gold, LinkedIn News, &lt;a href=&quot;https://www.linkedin.com/news/story/vc-funding-dries-up-for-startups-5679956/&quot;&gt;“VC funding dries up for startups”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-33&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-55&quot;&gt;
&lt;p&gt;Rodney Brooks, 2024, &lt;a href=&quot;https://rodneybrooks.com/predictions-scorecard-2024-january-01/&quot;&gt;“Predictions Scorecard, 2024 January 01”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-55&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-56&quot;&gt;
&lt;p&gt;“Financial Barriers”, CooperGibson Research, &lt;a href=&quot;https://assets.publishing.service.gov.uk/media/621ce8ec8fa8f54915f43838/Education_Technology_EdTech_Survey.pdf&quot;&gt;“Education Technology (EdTech) Survey 2020-21”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-56&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-57&quot;&gt;
&lt;p&gt;Kat Lay, The Times, &lt;a href=&quot;https://www.thetimes.co.uk/article/thousands-of-nhs-computers-still-vulnerable-to-hackers-fvs2q90vz&quot;&gt;“Thousands of NHS computers ‘still vulnerable to hackers’”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-57&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-58&quot;&gt;
&lt;p&gt;Olivia Powell, Cyber Security Hub, &lt;a href=&quot;https://www.cshub.com/attacks/news/uk-government-ministers-vulnerable-to-cyber-attacks&quot;&gt;“IOTW: Almost 50,000 UK government workers vulnerable to cyber attacks”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-58&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-59&quot;&gt;
&lt;p&gt;Richie Koch, Proton, &lt;a href=&quot;https://proton.me/blog/big-tech-2023-fines-vs-revenue&quot;&gt;“Big Tech has already made enough money in 2024 to pay all its 2023 fines”, January 8th 2024&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-59&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-38&quot;&gt;
&lt;p&gt;Engineers’ Council for Professional Development (1947), &lt;a href=&quot;https://books.google.ie/books/about/Canons_of_Ethics_for_Engineers.html?id=cGefHAAACAAJ&amp;amp;redir_esc=y&quot;&gt;“Canons of ethics for engineers”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-38&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-37&quot;&gt;
&lt;p&gt;David Beers, Mastodon, &lt;a href=&quot;https://dair-community.social/@davidbeers/111585474313351634&quot;&gt;“Rolling my eyes at…”&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-37&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item><item><title>Migrating AngularJS to Angular with a hybrid application</title><link>https://www.matt.si/2023-06/angular-migration/</link><guid isPermaLink="true">https://www.matt.si/2023-06/angular-migration/</guid><description>In January 2022, the last version of AngularJS left support. There will be no official updates or security patches for AngularJS ever again. Yet, many big organisations that invested in AngularJS early on still depend on it. How can we help these organisations to manage the move from AngularJS to Angular?</description><pubDate>Mon, 26 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;First posted on &lt;a href=&quot;https://www.codurance.com/publications/migrating-angularjs-to-angular&quot;&gt;the Codurance blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In January 2022, the last version of AngularJS left support. There will be no official updates or security patches for AngularJS ever again.&lt;/p&gt;
&lt;p&gt;Yet, many big organisations that invested in AngularJS early on still depend on it. How can we help these organisations to manage the move from AngularJS to Angular?&lt;/p&gt;
&lt;p&gt;First, a common cause of confusion: AngularJS and Angular are two separate things. Angular is sometimes also called Angular 2+. In short, at some point in AngularJS’ history it was decided to majorly rearchitect the whole thing in a new framework that kept the same name but dropped the “JS”, known as Angular. There is no upgrade path between them. The only way to go from one to the other is to migrate.&lt;/p&gt;
&lt;h2 id=&quot;why-not-some-other-ui-framework&quot;&gt;Why not (some other UI framework)?&lt;/h2&gt;
&lt;p&gt;Given that you might ask, why migrate at all? Why not re-implement everything in Vue or Svelte or some other exciting new framework? The biggest reason is that Angular provides features for working alongside AngularJS that make it much easier to migrate from one to the other. Namely, it allows you to run a “hybrid application” in which both Angular and AngularJS run side-by-side during the migration. This enables you to replace one small piece at a time. On the other hand if you use a totally different framework you most likely won’t be able to cleanly use them both in the same page, so you may need to migrate the entire application in one step.&lt;/p&gt;
&lt;p&gt;Now if you have only a very small and simple application it may not be a bad choice to change to another framework. But setting out to replace any sufficiently complex or large application in one “big bang” change is never going to work. To realistically change such applications you have to “change the wheels while the vehicle is moving”. That is, to avoid breaking the application for its users you must keep the application in a running, workable state at all times while iteratively replacing numerous parts of it.&lt;/p&gt;
&lt;p&gt;The other reason is just that Angular uses similar concepts and syntax to AngularJS, and your application’s developers will find it easier to learn than picking up something totally new.&lt;/p&gt;
&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;Unfortunately, though it is very much possible and the features exist in Angular to suport it, there aren’t many resources on how to actually create a hybrid application. The best resource on this topic is &lt;a href=&quot;https://go.nrwl.io/upgrading-angular-applications-book&quot;&gt;Upgrading Angular Applications&lt;/a&gt; by Victor Savkin, who is a member of the Angular team that has been very active on this topic. In my project we kept this book close-by at all times as a guide. Savkin’s book goes into much detail on the more conceptual side of things and includes some code samples, but there is also &lt;a href=&quot;https://angular.io/guide/upgrade&quot;&gt;the official Angular upgrade guide&lt;/a&gt; which is a bit light on the conceptual side but includes a lot of technical detail.&lt;/p&gt;
&lt;p&gt;In the best of cases though, I found the documentation to be very helpful yet not quite comprehensive enough. At this point you may choose to go and read the documentation I have linked instead and see where that takes you, but what follows from here will be my lessons learned having gone down the path you’re about to take already. Hopefully it helps.&lt;/p&gt;
&lt;h2 id=&quot;angular-and-angularjs-side-by-side&quot;&gt;Angular and AngularJS side-by-side&lt;/h2&gt;
&lt;p&gt;Every AngularJS or Angular application can be thought of as a tree, like so:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-angularjs.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-angularjs.jpg&quot; alt=&quot;A tree diagram in of blue nodes each representing AngularJS modules or directives.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this case each of those blue nodes are some AngularJS unit of code be they a module, or directive, or whatever. The root node must be a module, this is your app module that contains the whole application. From there you might imagine that the second row are directives representing whole pages, and the next row after that are directives making up small parts of those pages.&lt;/p&gt;
&lt;p&gt;What we want to achieve, in short, is this:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-1.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-1.jpg&quot; alt=&quot;A tree diagram as before but one leaf node of the tree is replaced by a red node, representing an Angular component&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If we could do this, we could replace one small directive of this whole tree with an Angular component. That would be amazing! If it continued to work as before then we could merge and deploy our changes without any users even noticing a change. That would enable us to follow true &lt;strong&gt;continuous integration&lt;/strong&gt;: making small changes that are merged and deployed constantly, always staying up-to-date with the main branch. This way each small piece gets tested and moved into production one bit at a time, meaning many small painless deploys instead of one big scary deploy if you were to migrate many or all nodes in one go. Also, it really helps to reduce version control conflicts and improve general team cohesion.&lt;/p&gt;
&lt;h3 id=&quot;ng-upgrade&quot;&gt;ng-upgrade&lt;/h3&gt;
&lt;p&gt;But is that possible? It is, thanks to &lt;code&gt;ng-upgrade&lt;/code&gt;. &lt;code&gt;ng-upgrade&lt;/code&gt; is a library Angular provides for adding a compatibility layer between Angular in AngularJS. It enables you to upgrade AngularJS directives to Angular and downgrade Angular components to AngularJS directives, and do similar for services and such.&lt;/p&gt;
&lt;p&gt;It does this by wrapping an object from one API in a wrapper object that translates between it’s API and the other. For example, to upgrade an AngularJS object it wraps an object around it that translates it’s outputs into an API that Angular understands and translates it’s inputs from Angular into a format that AngularJS understands. In terms of our diagram, that looks like this:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/ngupgrade.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/ngupgrade.jpg&quot; alt=&quot;A diagram demonstrating how an AngularJS node in the previous diagrams may be &amp;quot;upgraded&amp;quot;, resulting in a blue node wrapped in a red circle wrapper, and visca versa for downgrading Angular nodes.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Using this we can integrate our new Angular components with the old AngularJS application, like so:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-2.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-2.jpg&quot; alt=&quot;A tree diagram as before but one leaf node of the tree is replaced by a red node with a blue circle around it, indicating an Angular component that has been downgraded to act as an AngularJS directive&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;How we actually do this in code is very simple too. An example follows. Note that &lt;code&gt;angular.module&lt;/code&gt; is a regular AngularJS function (you will need &lt;a href=&quot;https://www.npmjs.com/package/@types/angularjs&quot;&gt;the types&lt;/a&gt; to reference them from Typescript) and only the inner value we’re placing in there is different, because we’re providing a wrapped Angular component downgraded using the &lt;code&gt;downgradeComponent&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;angular&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myModule&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;directive&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myDirective&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;downgradeComponent&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    component&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;MyComponent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  }))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is really cool! From here you can move one node at a time, from the bottom up, until the whole application is migrated, and keep the application working and deployable the whole time. But it is not a complete solution. In fact, it presents considerable problems. Imagine that you follow this approach and migrate all of the leaf nodes of this tree - which may have dozens, hundreds or even thousands of nodes in breadth - what then? You end up with a tree that looks a little like this:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-3.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-hybrid-3.jpg&quot; alt=&quot;A tree diagram as before but with only one blue AngularJS root node connected to many downgraded Angular components&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this scenario you’ve been working on this migration for at least months, perhaps years. Yet you don’t have any actual full Angular pages because everything depends on the AngularJS root module. And if you introduce new features they’ll have to include this AngularJS wrapper even if you write them in Angular.&lt;/p&gt;
&lt;p&gt;What’s more, now you have a big job ahead of you: Cutting out the AngularJS root module, and replacing it with an Angular one. This is a huge change: Every downgraded node now needs to have its downgrade removed, every service too, and any remaining AngularJS services that were upgraded need to be migrated. This is not only a big change to make in one go, it is also a risky one: It affects every single page in the entire application, and any of them could potentially break on some odd unforeseen edge case. So the amount of testing work is far greater than the amount of development work.&lt;/p&gt;
&lt;p&gt;All along you were creating a time bomb. How can we avoid this “time bomb” problem? Savkin introduces what he calls the Shell Strategy to help here.&lt;/p&gt;
&lt;h3 id=&quot;the-shell-strategy&quot;&gt;The Shell Strategy&lt;/h3&gt;
&lt;p&gt;In short, the shell strategy is: Wrap the root AngularJS module in an Angular module (using ng-upgrade to make the AngularJS module interoperate with the new root Angular module), effectively making the whole AngularJS application belong to an Angular application.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:500px;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-shell-strategy.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-shell-strategy.jpg&quot; alt=&quot;A tree of blue AngularJS nodes, but the blue root node is now wrapped in a red circle (an Angular upgrade wrapper) and has a red node parent above it.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In practice this is done by removing your original &lt;code&gt;.bootstrap&lt;/code&gt; or &lt;code&gt;ng-bootstrap&lt;/code&gt; calls for AngularJS and instead boostrapping AngularJS from Angular’s bootstrap, using the &lt;code&gt;upgrade.bootstrap&lt;/code&gt; function from &lt;code&gt;ng-upgrade&lt;/code&gt; that takes the exact same parameters as the original:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;NgModule&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; AppModule&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; DoBootstrap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; upgrade&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;UpgradeModule&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75;font-style:italic&quot;&gt;upgrade&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;UpgradeModule&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;upgrade&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; upgrade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;  ngDoBootstrap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75;font-style:italic&quot;&gt;appRef&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;ApplicationRef&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;    appRef&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;bootstrap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;AppComponent&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;upgrade&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;bootstrap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;root-template-element&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Element&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, [&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;my-dependencies-here&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has one immediate, obvious advantage- You can now add pure Angular routes and pages without any AngularJS, like so:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:500px;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-shell-strategy-2.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/tree-shell-strategy-2.jpg&quot; alt=&quot;As the previous tree diagram but now the root red node has another red (Angular) node running off of it, into a separate branch with no blue (AngularJS) nodes.&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This way we can add full new features in Angular without any AngularJS! But if we were to take this top-down strategy to its logical conclusion it would have us apply the &lt;code&gt;ng-upgrade&lt;/code&gt; wrapper to all the top-level AngularJS nodes which is just not workable. There are a couple different strategies that Savkin describes in his book, but we went with a bottom-up strategy along with the shell strategy. That way we can incrementally migrate one part of the tree at a time until an entire branch can be moved to pure Angular:&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Four tree diagrams demonstrating, one step at a time, how a branch of nodes may be converted one at a time until the whole branch is moved to the Angular root node&quot; src=&quot;https://www.matt.si/tree-shell-strategy-3.gif&quot; width=&quot;500px&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We follow a “bottom-up” pattern, aka migrate a leaf node of the tree first, because it is the simplest place to start. If you migrate a node in the middle of your tree you need to use upgrade and downgrades to manage the relationships that node has above &lt;em&gt;and&lt;/em&gt; below it, but with the leaf node you only need to upgrade that one node and then it can talk to its parents.&lt;/p&gt;
&lt;p&gt;This way you can incrementally, continuously grow the Angular application while shrinking the AngularJS application. And we end up with a whole branch in pure Angular! Rather than ending up with a load of partially converted unfinished pages, you’ve completed a few simple self-contained parts without once breaking the site until a whole section of it is totally converted. This is a really compelling approach to a project stakeholder. I suggest you keep track of how many AngularJS controllers there are and how many Angular components and graph them over time, this gives you a clear metric you can report demonstrating the pace and continued progress of the migration.&lt;/p&gt;
&lt;h2 id=&quot;routing&quot;&gt;Routing&lt;/h2&gt;
&lt;p&gt;Remember that in both AngularJS and Angular you can route your applications by providing an element in your root template that gets replaced by the contents of the page being routed to.&lt;/p&gt;
&lt;p&gt;In terms of how this looks in the root HTML template of a hybrid application, you’ll want to have the roots of your Angular and AngularJS applications side-by-side like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; ng-view&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;app-root&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;app-root&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Any pages your AngularJS application routes to will be displayed under your &lt;code&gt;ng-view&lt;/code&gt; element, and pages your Angular application routes to will be displayed under your &lt;code&gt;app-root&lt;/code&gt; element (or replace &lt;code&gt;app-root&lt;/code&gt; with whatever selector you specify in your app component, typically named &lt;code&gt;app.component.ts&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;But, you might think, surely this renders both applications on the same page? Well, yes, it does. And that opens a whole other can of worms to think about. You can ensure that only one page is displayed by having the other application display a blank page. Like so:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/routing.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-06/angular-migration/routing.jpg&quot; alt=&quot;A diagram showing three URL paths 1, 2 and 3 going through two shapes one after the other. The first shape is labelled &amp;quot;Angular&amp;quot; and takes control of path 1. The second shape is labelled AngularJS and it controls paths 2 and 3&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But there are a couple possible bugs: What if both applications don’t control a route, and thus show nothing? What if they both think they control it, and thus both applications display a page at the same time?&lt;/p&gt;
&lt;p&gt;The first issue is easily resolved: Just ensure that only one of the applications has a 404 page. Then if the user routes to a page that neither of them controls, one of them will display a 404 page and the other nothing. Just ensure that there is only one application responsible for 404 pages.&lt;/p&gt;
&lt;p&gt;As for the second problem, that is a bit more difficult. If you migrate a page there is a risk that the old page may not be properly removed and both applications may display something at the same time, especially if there is some non-trivial additional logic to your routing. In most moderately-sized applications it is probably enough to just trust the developers to catch these errors manually. In our quite big, complex case we came up with a more comprehensive solution: Specify all of your Angular routes in a JSON file the new application exposes and read it (once at startup) from the AngularJS application. We then modified the AngularJS router to throw an error if it is told to add a route to a route that we know is controlled by AngularJS. Using this method we were also able to add feature flags to individual routes.&lt;/p&gt;
&lt;h3 id=&quot;route-syncing&quot;&gt;Route syncing&lt;/h3&gt;
&lt;p&gt;Routing was perhaps the most awkward, finicky issue of the hybrid application my team and I worked on. There were a couple particular bugs that caused a lot of trouble: Recursive loops in which AngularJS causes a routing event in Angular, which in turn causes an event in Angular, which in turn causes an event in AngularJS, ad infinitum. Often this happened because they each disagreed on what the correct name for the path was, which mostly comes down to differences in behaviour in certain edge cases regarding how Angular and AngularJS parse URLs. When it comes to this, we had to write our own &lt;a href=&quot;https://angular.io/api/router/UrlSerializer&quot;&gt;&lt;code&gt;UrlSerializer&lt;/code&gt;&lt;/a&gt; to configure how Angular serialises and deserialises URLs. So long as it reads in addresses from AngularJS correctly and outputs ones that AngularJS can read, it will work fine.&lt;/p&gt;
&lt;p&gt;The other issue was the opposite: Sometimes, when AngularJS triggered a routing event it wouldn’t be recognised by Angular. This would result in incorrect states where both applications are rendering a page at the same time because Angular has not received a routing event so does not know that it needs to display nothing, but AngularJS is aware of ther event hence is rendering something.&lt;/p&gt;
&lt;p&gt;The solution to this is simple: &lt;code&gt;ng-upgrade&lt;/code&gt; provides a tool called &lt;a href=&quot;https://angular.io/api/router/upgrade/setUpLocationSync&quot;&gt;&lt;code&gt;setupLocationSync&lt;/code&gt;&lt;/a&gt; that ensures all AngularJS routing events are matched in Angular. All you have to do is call the function during your Angular bootstrap. For most people this will be enough but if you are using fragment-style addresses (ie your URLs have a &lt;code&gt;#&lt;/code&gt; in them before the front-end page address, like &lt;code&gt;my.website.com/index.jsp#/about-us&lt;/code&gt;) then you will have another complication. Your luck may vary but we found that setUpLocationSync does not work for this type of address by default. Luckily it is quite a simple function, so we just copied it &lt;a href=&quot;https://github.com/angular/angular/blob/9d4842cadb89dbb1a7ceb53d2f35213c9924ff97/packages/router/upgrade/src/upgrade.ts#L65&quot;&gt;from source&lt;/a&gt;, wrote some tests around it and produced a custom version that works with fragment URLs.&lt;/p&gt;
&lt;h2 id=&quot;upgrading-and-downgrading-services&quot;&gt;Upgrading and downgrading services&lt;/h2&gt;
&lt;p&gt;One problem you’re likely to come across is sharing services between both applications. You’ll have pages in AngularJS you want to migrate to Angular but they use services that are shared by other AngularJS pages. In this case you have three possible approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Re-implement the service in Angular, keeping two copies of the same service.&lt;/li&gt;
&lt;li&gt;Re-implement the service in Angular, delete the AngularJS one and use a downgrade wrapper to make the Angular version usable by AngularJS code.&lt;/li&gt;
&lt;li&gt;Add an upgrade wrapper to the AngularJS service that makes it available in Angular. After all the pages using it have been migrated, then the service itself can be migrated and the wrapper removed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of these options are viable and it depends on the specifics of the particular service which one is the best choice. Honestly, though it may not be your first choice, option 1 is not bad at all. Yes you’re creating duplication, but so long as everyone is on the same page that we’re working on the Angular version exclusively from now on it isn’t much of a problem. It doesn’t work however if your service has state - don’t try doing something silly to sync them together it really isn’t worth it, just choose option 2 or 3. 1 can also not be a good choice when a service is used in very many places and is likely to be modified. If you’re likely to change it and unlikely to be able to complete migrating it before then, just follow options 2 or 3.&lt;/p&gt;
&lt;p&gt;To choose between options 2 or 3 you have to decide whether you want to front-load or back-load the effort: Migrate the service add a lot of Angular downgrade wrappers to a lot of AngularJS pages right now that you can remove later? Or save yourself from doing that by adding one AngularJS upgrade wrapper each time you migrate a component or page, but with the knowledge that you’ll eventually have to perform that migration and remove all the wrappers? I would lean toward back-loading the effort: Make your immediate job simpler, follow the simplest implementation you can think of, and put a task to follow up with migrating that service in your backlog.&lt;/p&gt;
&lt;p&gt;Actually making an Angular service available in AngularJS is, similar to downgrading a component, very simple:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;angular&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myModule&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myService&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;downgradeInjectable&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;myService&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upgrading an AngularJS service is a bit more involved because you have to add types for the relevant service in TypeScript, but it is still quite easy. You add the service to the providers array of one of your modules, in the &lt;code&gt;@NgModule&lt;/code&gt; annotation. Like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;angular&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myModule&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, [])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;factory&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;myService&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;downgradeInjectable&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;myService&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upgrading an AngularJS service is a bit more involved because you have to add types for the relevant service in TypeScript, but it is still quite easy. You add the service to the &lt;code&gt;providers&lt;/code&gt; array of one of your modules, in the &lt;code&gt;@NgModule&lt;/code&gt; annotation:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;providers: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    deps: [&apos;$injector&apos;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    provide: &apos;my-service-name&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    useFactory: (injector: Injector) =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      return injector.get(serviceName)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;Injector&lt;/code&gt; is capable of fetching the AngularJS service, and by passing that into providers via &lt;code&gt;useFactory&lt;/code&gt; you make it available for general use in your Angular application.&lt;/p&gt;
&lt;p&gt;However, my recommendation would be not to use this service directly in any components. Instead, create a new Angular service that wraps this one, provides a similar API and delegates actual behaviour to the AngularJS service. That way when the time comes to migrate that service you have a much easier time untangling the AngularJS version as it is only used in one place, not many, and you can simply implement the same logic in your Angular service using the API you defined. You can inject the underlying service you specified into your new wrapper service in the constructor like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; constructor&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Inject&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;my-service-name&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; myInnerService&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;MyInnerService&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) { }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the argument you pass to &lt;code&gt;@Inject&lt;/code&gt; must be exactly the same as the string (known as the token) you pass to the &lt;code&gt;provide&lt;/code&gt; argument when defining the provider above.&lt;/p&gt;
&lt;h2 id=&quot;training&quot;&gt;Training&lt;/h2&gt;
&lt;p&gt;The developers that were accustomed to AngularJS will need a bit of training to get up to speed. They’ll now need to write in TypeScript which is quite a different language, and Angular itself has significant differences too. You’ll need to lead these efforts to ensure that the developers have all the support they need.&lt;/p&gt;
&lt;h3 id=&quot;courses&quot;&gt;Courses&lt;/h3&gt;
&lt;p&gt;For Typescript, I recommend &lt;a href=&quot;https://www.totaltypescript.com/tutorials/beginners-typescript&quot;&gt;Beginner’s Typescript&lt;/a&gt; from TotalTypescript. It’s a very practical series of tutorials in which you do most everything yourself, and it is written in a way that assumes you know Javascript reasonably well already and only introduces the new concepts. For Angular, the &lt;a href=&quot;https://angular.io/tutorial&quot;&gt;official tutorials&lt;/a&gt; are very good. I found that Tour of Heroes teaches you all the fundamentals.&lt;/p&gt;
&lt;p&gt;Other than those the Pluralsight courses for Typescript and Angular I know to be quite good, and Udemy has courses for them too though I’ve not looked closely at those.&lt;/p&gt;
&lt;h3 id=&quot;knowledge-sharing&quot;&gt;Knowledge sharing&lt;/h3&gt;
&lt;p&gt;Ultimately if you are the team architecting the migration you will be the ones with the knowledge that the rest of the company needs, and the responsibility to disseminate it. Sending some developers on courses won’t be enough.&lt;/p&gt;
&lt;p&gt;We found that hosting seminars and Community of Practice (as part of a Continuous Improvement Program) helped. Nothing can substitute having actual conversations, answering questions. And the closer you can work with the developers, the better! Pair with them, work on your backlog items with them, get them real experience working in this new way with the support of someone that already has familiarity right there.&lt;/p&gt;
&lt;p&gt;Better yet, use &lt;strong&gt;rotational coaching&lt;/strong&gt;: Invite a few developers from another team into your team, have them pair with you for a sprint, then let them return to their team bringing their learnings to their team. Then, you can pick a few developers from a different team to join you on your next sprint. This can be a really effective way of disseminating information throughout the organisation.&lt;/p&gt;
&lt;p&gt;And if your developer experience is great then each developer you coach will become an advocate of your project, too. They will help spread the excitement of your migration to their contacts, increasing the chance that more teams will want to get involved.&lt;/p&gt;
&lt;h2 id=&quot;finding-help&quot;&gt;Finding help&lt;/h2&gt;
&lt;p&gt;When involved in a complex project like an Angular migration it is not uncommon to come across strange edge cases that there is not a lot of material for online. In these cases it really helps to have someone to talk to. I recommend joining the &lt;a href=&quot;https://discord.com/invite/angular&quot;&gt;Angular Discord Community&lt;/a&gt; for that reason. I found them really helpful on several occasions when I was struggling against some weird bugs. There is also a Greppr community, but in my experience the Discord is far more active.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;We’ve covered how to create a hybrid Angular-AngularJS architecture, how that is essential in migrating an AngularJS application to Angular, and strategies for doing so. I hope you find this helpful because in my experience there just wasn’t quite enough information about Angular hybrid applications online.&lt;/p&gt;
&lt;p&gt;Migrating to Angular is no small task, but if you decide to go that route it is definitely doable. Best of luck.&lt;/p&gt;</content:encoded></item><item><title>Introduction to Test Driven Development (TDD)</title><link>https://www.matt.si/2023-06/intro-to-tdd/</link><guid isPermaLink="true">https://www.matt.si/2023-06/intro-to-tdd/</guid><description>A video presentation into to TDD- what it is, why we practice it, how to practice it</description><pubDate>Sat, 10 Jun 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After a while of attending the &lt;a href=&quot;https://www.meetup.com/london-software-craftsmanship/&quot;&gt;London Software Craftsmanship Community&lt;/a&gt; and running events there I noticed that quite a few people didn’t really understand Test Driven Development (TDD), a practice I and my coworkers use to develop software every day. So I arranged an event in which I explained the fundamentals of TDD and my colleague Ignacio Gonzalez gave a demonstration, then got the attendees working on some problems and practicing TDD. It was well received and afterwards several people suggested we record it as a video/screencast to share online. So, we did! Check it out:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/LrUTkGkJ-nQ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title>Rust Screenkatas</title><link>https://www.matt.si/2023-05/rust-screenkatas/</link><guid isPermaLink="true">https://www.matt.si/2023-05/rust-screenkatas/</guid><description>Recently I&apos;ve published a few screencasts solving programming challenges in Rust. Come</description><pubDate>Thu, 18 May 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I’ve published a few screencasts solving programming challenge katas with Codurance (part of the screenkatas series) in Rust. The first is a basic introduction, installing Rust and writing a basic FizzBuzz. The next two are parts of a two-parter which is a bit more complex, solving the N-Queens problem with TDD. I also take time to explain the theory behind search problems and the N-Queen problem in particular using diagrams.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/GON3Ebg-Z9k&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/5NHYNFM4XUA&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/45ShXM9hwJc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;If the jump in complexity from FizzBuzz to N-Queens is a bit dizzying, my colleague Jocelyn also published this great screencast on solving the Mars Rover kata with Rust:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/LKrHLdXOcnc&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title>Rust Nation 2023 Review</title><link>https://www.matt.si/2023-02/rust-nation/</link><guid isPermaLink="true">https://www.matt.si/2023-02/rust-nation/</guid><description>A review of Rust Nation 2023! Delivering a day-long workshop, meeting cool people, attending great talks…</description><pubDate>Tue, 21 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past week I attended Rust Nation 2023, a two-day conference and the UK’s first-ever Rust conference, and even delivered a day-long workshop. It had massive attendance and really drove home just how big and active the Rust community is. In this post I’ll share what I learned and my experiences at the con, and hopefully entice you to join us next year if you weren’t there this time.&lt;/p&gt;
&lt;h2 id=&quot;day-one---delivering-a-foundational-workshop&quot;&gt;Day One - Delivering a Foundational Workshop&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/workshops-speaking.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/workshops-speaking.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Rust Nation was split into two days, the first day being the workshop day and the second being the conference day. The workshop day featured three day-long workshops: Foundational (beginner), intermediate, and async (advanced). As the Workshop Partner, Codurance ran two of the workshops: Myself running the foundational track, and my colleague &lt;a href=&quot;https://hachyderm.io/@jsfacchini&quot;&gt;Jocelyn Facchini&lt;/a&gt; running the intermediate track.&lt;/p&gt;
&lt;p&gt;We worked closely together on the content for both. We re-used much of the content from &lt;a href=&quot;https://www.matt.si/2022-05/macros-what-why-how/&quot;&gt;my talk on macros last May&lt;/a&gt; for the intermediate track’s macro section, and Jocelyn came up with a really cool exercise for it inspired by the “Building the json! Macro” chapter of O’Reilly’s Programming Rust (2021). We also did many dry-runs together of both workshops along with our teaching assistants that were of great help to us on the day, &lt;a href=&quot;https://www.linkedin.com/in/ikatzarski/&quot;&gt;Ivan Katzarski&lt;/a&gt; and &lt;a href=&quot;https://www.linkedin.com/in/benjaminhedges/&quot;&gt;Benjamin Hedges&lt;/a&gt; (Codurance) and &lt;a href=&quot;https://twitter.com/yefoakira&quot;&gt;Jorge Gueorguiev&lt;/a&gt; (Equal Experts, formerly Codurance).&lt;/p&gt;
&lt;p&gt;All that is just to say that: It was a lot of work and I was lucky enough to collaborate with some great people. As for the day itself, all that work paid off because it went off without a hitch with very few hitches!&lt;/p&gt;
&lt;p&gt;I had a lot of content prepared already for the foundation workshop from my &lt;a href=&quot;https://www.matt.si/2022-04/intro-to-rust-talk/&quot;&gt;Introduction to Rust talk&lt;/a&gt; and workshops that I had run at the London Software Craftsmanship Community, but this was twice as long as the workshop I’d run before so it needed a lot of new content. The broad idea of the foundation workshop was to, as the name implies, teach the &lt;em&gt;foundations&lt;/em&gt; of the language. We delved deep into ownership &amp;amp; borrowing, explaining exactly what the compiler is doing at a low level. Then we covered much of the common types and syntax you need to know to get started with Rust and went over error handling and testing, before bringing it all together by writing a small project using what we’d learned. Finally, I shared many great further study resources for those that want to continue their Rust journey.&lt;/p&gt;
&lt;p&gt;I knew from the start that it was a very ambitious amount of content to deliver, so I intended for the final section- the small project- to be something we didn’t finish on the day but something we could start on, and included a lot of detail and even a finished solution in the exercise itself so that attendees could finish it in their own time. And that seemed to go down well. I even met an attendee just the next day who had gone home and finished the exercise right after the workshop finished.&lt;/p&gt;
&lt;p&gt;All in all I’m really happy with how it went and open to doing more workshops, tutorials, and the like in the future.&lt;/p&gt;
&lt;h2 id=&quot;day-two-session-one---grand-opening&quot;&gt;Day Two, Session One - Grand Opening&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/opening_keynote.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/opening_keynote.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Photo from &lt;a href=&quot;https://twitter.com/FastlyDevs/status/1626527876668440576/photo/1&quot;&gt;@FastlyDevs on Twitter&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The opening talk was from Nell Shamrell-Harrington, Principal Developer at Microsoft and a member of the Rust Foundation board. The talk was all about the Rust community and included a great number of quotes from various figures that almost served as a rolodex of many of the most prominent figures in the community. It highlighted how uniquely inclusive and supportive the Rust community is, and I completely agree. So many times I’ve found total strangers willing to volunteer their time and energy in helping me study Rust, whether from Discord, Reddit, or from volunteer mentors on Exercism.&lt;/p&gt;
&lt;p&gt;Nell also pointed out that, due to the rate of exponential growth the community is seeing, if you’ve been programming Rust for over a year then you likely have more experience with it than half the Rustaceans out there. That is a really interesting point and I think emphasises the need for those of us who’ve been studying Rust for even just one or two years to be as inclusive and supportive as possible. We need to show the same behaviour others have shown to us, to those just trying Rust for the first time and so keep that great community culture going.&lt;/p&gt;
&lt;h2 id=&quot;day-two-session-two---tockos-tutorial&quot;&gt;Day Two, Session Two - TockOS Tutorial&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/tockOS.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/tockOS.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For the second session, I attended Irina Bradu’s TockOS Tutorial. I wasn’t able to stay for the full duration, but I always find it interesting and fun to play with embedded code devices. In this session, Irina supplied a whole load of Pico Explorer devices and the idea of the tutorial was to set up a simple IoT device that could control temperature sensors and such.&lt;/p&gt;
&lt;p&gt;TockOS is an embedded operating system. The tutorial involved setting up a Pico Explorer as a sort of IoT hub that could pull in data from sensors and use them to set your thermostat automatically. It’s an exciting idea to me because I’d like to have some home automation but I don’t trust the big IoT providers that want to store all your data “in the cloud”, but it also seems like a significant amount of work to maintain.&lt;/p&gt;
&lt;h2 id=&quot;day-two-session-three---meeting-the-game-developers&quot;&gt;Day Two, Session Three - Meeting the Game Developers&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/gamejam.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/gamejam.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Image from &lt;a href=&quot;https://twitter.com/AngelOnFira/status/1626688227280306176&quot;&gt;Forest Anderson on Twitter&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In this session I was looking for one talk, couldn’t find the room, and ended up stumbling into a different room entirely where &lt;a href=&quot;https://twitter.com/jsbarretto&quot;&gt;Joshua Barretto&lt;/a&gt; and &lt;a href=&quot;https://twitter.com/AngelOnFira&quot;&gt;Forest Anderson&lt;/a&gt; were running a “micro game jam”. They are two of the core developers of &lt;a href=&quot;https://veloren.net/&quot;&gt;Veloren&lt;/a&gt;, probably the most prominent game developed in Rust right now, and Forest is a member of the Rust Game Development Working Group.&lt;/p&gt;
&lt;p&gt;They actually wrote their own micro game engine just for this conference, which is the coolest thing. I sat down and had a play with it with the idea of writing some simple demo but didn’t get far because I ended up doing my favourite thing to do at these events: Chatting to interesting people in tech. So I spent most of this session talking to Joshua and Forest about voxel game engines, multi-agent systems in simulations, and the Rust community in the UK.&lt;/p&gt;
&lt;p&gt;During this conversation we discovered that Barretto and I had &lt;a href=&quot;https://todon.eu/@jsbarretto@social.coop/109596960001321798&quot;&gt;met online once before&lt;/a&gt;. It is funny to realise that someone you’ve met in real life is the same person as some identity you know online - your mind now maps these two identities where there wasn’t a link before. It’s like when you discover a new shortcut on your commute and suddenly your mental map of the area changes.&lt;/p&gt;
&lt;h2 id=&quot;day-two-session-four---moving-past-proof-of-concept&quot;&gt;Day Two, Session Four - Moving Past Proof of Concept&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/mcnamara_keynote.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/mcnamara_keynote.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Tim McNamara delivered a keynote in session four on the topic “Moving past Proof of Concept”. I was also lucky enough to briefly meet McNamara at the RedBadger event on Saturday too, though I didn’t realise that I was talking to the author of Rust In Action until part-way through the conversation.&lt;/p&gt;
&lt;p&gt;I made a few notes that I thought were interesting points from the talk:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Going by various metrics, the Rust community’s growth appears to be exponential - things are going to change fast if this momentum continues&lt;/li&gt;
&lt;li&gt;It is not enough to persuade your clients or employers to give Rust a try. To ensure the longevity of Rust you need to have a really strong case.
&lt;ul&gt;
&lt;li&gt;Rust may be able to eliminate almost all memory bugs that currently plague non-garbage-collected languages. McNamara quoted numerous interesting sources that showed staggering amounts of preventable memory-related issues that can have a very high impact in terms of maintenance, user satisfaction, and security.&lt;/li&gt;
&lt;li&gt;He also highlighted energy conservation, and this was a point I saw come up several times at the conference that I found interesting. If I recall correctly, he quoted one study in which a company migrated their horizontally-scaling service to Rust and found that they could reduce their number of nodes by 70% as a result - what a huge saving in energy! In a world where &lt;a href=&quot;https://www.irishtimes.com/news/ireland/irish-news/data-centres-now-consuming-more-electricity-than-rural-homes-cso-1.4868221&quot;&gt;Ireland spends more energy on data centres than in all its rural homes&lt;/a&gt;, that could mean a huge difference.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;He also listed a few project ideas for newcomers to Rust to try, and highlighted the need for more people that have a desire for one library or another to exist to publish these so that newcomers looking to write some Rust have an idea of what needs to be done
&lt;ul&gt;
&lt;li&gt;Reimplement &lt;code&gt;std::Cell::cell&lt;/code&gt; - apparently this is an interesting look into the standard library&lt;/li&gt;
&lt;li&gt;Add a snippet to the Rust Cookbook&lt;/li&gt;
&lt;li&gt;Write a chatbot - a project that is very much achievable and yet massively extensible, depending on just how far you want to go.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;day-two-session-five---surrealdb&quot;&gt;Day Two, Session Five - SurrealDB&lt;/h2&gt;
&lt;p&gt;This session was a little over-subscribed so I was sitting on the floor near the back and couldn’t follow along too well. Nonetheless, it was an interesting presentation: part introduction to SurrealDB and part discussion of why they chose to write it in Rust. In short, they used Go in the past and found great performance improvements and cost savings by switching to Rust.&lt;/p&gt;
&lt;p&gt;I haven’t had the chance to play with it yet, but SurrealDB seems like an interesting project. It is a “multi-model database”, so you can use it to create a typical table-based relational DB or a document store or a graph database all under the same roof, sharing authentication and connections and such. It is designed to be a cloud-native scalable platform, with a particular focus on serverless and JAMStack apps.&lt;/p&gt;
&lt;h2 id=&quot;day-two-session-six---rust-foundation-qa&quot;&gt;Day Two, Session Six - Rust Foundation Q&amp;amp;A&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/rust_foundation.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/rust_foundation.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Image from &lt;a href=&quot;https://twitter.com/rust_foundation/status/1626611878062600194/photo/1&quot;&gt;@rust_foundation on Twitter&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In one of the last sessions of the day I attended the Rust Foundation panel session facilitated by Ernest Kissiedu, with panellists Rebecca Rumbul (CEO), Joel Marcy (CTO), Paul Lenz (finance), and Stephen Chin (newest director, works at JFrog). I didn’t know anything about how Rust is governed so this was very interesting. A few notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a distinction between “The Rust Project” and “The Rust Foundation”. The foundation apparently oversees various aspects of the Rust community, grants programs, and funding for various other initiatives but does not get directly involved in the Project, which is the development of the language and compiler itself. They do their best to support and provide whatever it is the Project needs, but the Project have full autonomy to decide what direction to take the language in.&lt;/li&gt;
&lt;li&gt;The Rust Foundation is growing - Joel was until not long ago the only technical member, but now they are up to 6 full-time technical staff.&lt;/li&gt;
&lt;li&gt;Joel notes that though the growth of Rust is great, it has put a lot of strain on their infrastructure - I’m not sure exactly what infrastructure he’s referring to, but I imagine crates.io would be the biggest problem
&lt;ul&gt;
&lt;li&gt;As such, a big goal for next year is to optimise the infrastructure to reduce costs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rebecca made the point that a lot of businesses are waking up to the importance of security, but while Rust can certainly help they will be disappointed if they think it is a magic bullet.&lt;/li&gt;
&lt;li&gt;Paul made several interesting points regarding finance. They want to expand their grants program and support as much open source-software and grassroots communities as possible. They will need more funding for this and he points out that many big organisations are making millions from open-source software and not paying back to the community, so there need to be “better ways of guilting these organisations”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;day-two-session-seven---living-with-rust-long-term&quot;&gt;Day Two, Session Seven - Living with Rust Long-Term&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/gjenset_keynote.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2023-02/rust-nation/gjenset_keynote.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The final keynote of the day came from Jon Gjengset. Having only been involved in the Rust community for a year or so and being bad with names and faces I often didn’t recognise some of the prominent characters or mixed up who had written this book or that software library. But unlike most of the many notable authors at the event I had read Gjengset’s book, Rust for Rustaceans, and also seen some of his videos, so I was a bit more familiar with him.&lt;/p&gt;
&lt;p&gt;Gjengset’s talk seemed to nicely tie into McNamara’s talk - they both had a broadly similar theme of: Going beyond migrating small modules to Rust and so forth, what concerns do we need to be aware of when it comes to developing serious amounts of code in this novel language long-term? This talk focused on the concerns you need to be thinking of now if you plan to maintain a Rust codebase for years or decades, and a lot of it was around dependency management. My notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rust guarantees backward compatibility for a given edition. And because different crates can be built with different editions, you can upgrade your edition without causing any compatibility issues with your dependencies.&lt;/li&gt;
&lt;li&gt;Suggests that lints should be warnings, not errors, i.e. not fail your CI, and to come up with a “batch process” for regularly tackling these.
&lt;ul&gt;
&lt;li&gt;This batch process may also include other steps like retrofitting new features to your codebase. You don’t want to do this when you upgrade because upgrading may then be a much bigger, slower process, but it is worth doing when you make time for it later.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;He strongly encourages everyone to stay up-to-date on the latest software and to avoid unstable features (Rust nightly) as much as possible
&lt;ul&gt;
&lt;li&gt;Updates give passive improvements - even if you don’t use the latest greatest feature, there are many less flashy improvements included that will make a difference to your performance and reliability&lt;/li&gt;
&lt;li&gt;Unstable features may change and cause regressions in your codebase&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;He also made some interesting points about crate abandonment, which I’ve found to be a big problem in NPM projects. He advised:
&lt;ul&gt;
&lt;li&gt;Be selective about what dependencies you add: ask yourself if you’re confident whether this crate will be supported in 10 years’ time.&lt;/li&gt;
&lt;li&gt;Use Cargo-Audit to check for any supply problems with your dependencies&lt;/li&gt;
&lt;li&gt;If a crate is abandoned, don’t stay with it. Do the work to migrate.&lt;/li&gt;
&lt;li&gt;If you notice that a crate is abandoned you can report it to Cargo-Audit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Rust Nation was great fun, and exceptionally tiring. It was wonderful to take part in the UK’s first Rust conference, to meet so many people that previously were just profile photos on a screen, and to get a real feel for just how huge the momentum behind Rust is right now.&lt;/p&gt;</content:encoded></item><item><title>ChatGPT Can Do Astonishing Things. But Is It a Helpful Development Tool?</title><link>https://www.matt.si/2022-12/chatgpt/</link><guid isPermaLink="true">https://www.matt.si/2022-12/chatgpt/</guid><description>A chatbot that can write code. The reaction to ChatGPT has been very polarising - some reactions very hyperbolic, others overly cynical. I explore what practical uses it has and ponder about where this might lead.</description><pubDate>Mon, 12 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On November 30th OpenAI &lt;a href=&quot;https://chat.openai.com/&quot;&gt;published a chatbot called ChatGPT&lt;/a&gt; that allows anyone to interact with their latest, greatest language model. You can ask it to do various things for you like writing screenplays, explaining difficult concepts or, most impressively, writing code. Since then it has made headlines for making programmers fret about their career prospects, getting banned from StackOverflow, and for &lt;a href=&quot;https://twitter.com/NickEMoran/status/1598101579626057728&quot;&gt;writing poems about hotwiring cars&lt;/a&gt;. For the past week, I’ve been playing around with this bot on and off to see what it can do, what its limitations are, and what practical use cases it may have.&lt;/p&gt;
&lt;p&gt;The reaction to ChatGPT amongst techies and software developers has been very polarising. I’ve seen some people acting hyperbolic about what it can do and what it means, and I’ve seen many people reacting cynically to it and denying it has any value at all. The truth is somewhere in the middle: ChatGPT has real value and is a big achievement, but we must restrain our excitement with skepticism because there are some major limitations to what ChatGPT can do.&lt;/p&gt;
&lt;h2 id=&quot;what-is-chatgpt&quot;&gt;What is ChatGPT?&lt;/h2&gt;
&lt;p&gt;Let’s get the obvious thing out of the way first: It is not an AI. In the strict sense of the term, humans have never produced an artificial intelligence and no one can say whether we ever will. It does use techniques derived from AI research, however. ChatGPT is a bundle of statistics and probability theory trained with an astonishing amount of compute and data that enable it to &lt;em&gt;predict what response you want from any given input&lt;/em&gt;. You type in some text, it outputs some text that it thinks will please you. It has read many many conversations between humans and figured out how to generate some letters in a particular sequence that is pleasing to the humans that supervised its learning, and the users it has learned from since then. This is similar to how DALL-E 2, OpenAI’s image generator bot, generated the image in the heading of this article. It has been trained on images of robots and keyboards, and it simply did its best to estimate the image I might be looking for.&lt;/p&gt;
&lt;p&gt;As such you can argue that it is not meaningfully “intelligent”. It is not even as smart as an average calculator. You can test and prove this easily for yourself. Try using ChatGPT like a calculator: ask it to solve mathematical equations. It will get simple ones perfectly correct but if you start making them long and adding a mixture of multiplication and division it will start to make mistakes and output nonsense results, even though a calculator from 1950 could have solved the same equation correctly in a split second. What is going on there? Well, ChatGPT was not designed to be a calculator. It cannot perform arithmetic operations. It was designed to produce a likely answer that it finds is most likely to please you.&lt;/p&gt;
&lt;h2 id=&quot;can-it-code&quot;&gt;Can it code&lt;/h2&gt;
&lt;p&gt;Despite this, ChatGPT does indeed have an incredible ability to write code. I sat down with 20 or so of my colleagues and ran a session in which we tested ChatGPT’s code-writing abilities. At one point we copied the definition of the &lt;a href=&quot;https://www.codurance.com/katalyst/simple-mars-rover&quot;&gt;Simple Mars Rover kata&lt;/a&gt; into the chat box and asked OpenAI to write an implementation in Rust that solved the problem. This is somewhat of a niche programming problem so we didn’t expect much. It immediately produced a solution that compiled, ran, and produced correct results:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;collections&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;HashMap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;// Define a struct to represent a rover&apos;s position and direction.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    x&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    y&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;i32&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;// Define a function to move the rover based on a given set of commands.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; move_rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;commands&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Define a map of directions to their left and right turns.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; directions&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; [(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;W&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)), (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;S&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;W&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)), (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;S&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)), (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;W&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;S&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;))];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; direction_map&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;HashMap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;char&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; &amp;amp;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; directions&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;iter&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;        direction_map&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;insert&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Iterate over the commands and update the rover&apos;s position and direction.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; c&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; commands&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;chars&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        match&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; c&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;            &apos;L&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;left&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; direction_map&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;[&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;                rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; left&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;            &apos;R&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;                let&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;right&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; direction_map&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;[&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;                rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; right&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;            &apos;M&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;                // Update the rover&apos;s position based on its current direction.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;                match&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;                    &apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.y &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.y + &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;                    &apos;S&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.y &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.y + &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;                    &apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.x &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.x + &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;                    &apos;W&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.x &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.x + &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;9&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;) % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;                    _&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; (),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;            _&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; =&amp;gt; (),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is an interesting solution. It has helpful comments, but not so many that it becomes problematic. It is very short at just 44 lines, yet very readable. It makes good use of Rust-specific language features, like  &lt;code&gt;match&lt;/code&gt;. It uses a direction map, which is often regarded as a very good trick for solving Mars Rover. It even implements world wrapping in a very simple and neat manner, using the mod operator on lines 34-37.&lt;/p&gt;
&lt;p&gt;The only things I can fault about it are the awkward way in which it goes about setting up the map, the fact that the map is initialised every time rather than being a one-time constant and using &lt;code&gt;char&lt;/code&gt; for direction rather than an enum. But overall, it is at least as good as I could do and it did it in a few seconds rather than maybe 40 minutes.&lt;/p&gt;
&lt;p&gt;Such a good result is the exception and not the rule, I should add. Most other tests I performed produced bugs or compile errors that needed to be solved. This is a fundamental limitation because ChatGPT does not have access to, nor even understand how to use, the compiler. It cannot verify that its code will compile. The fact that it managed to produce code that compiled first-time in that situation is incredible, honestly. But in most of my experiments it made small syntax errors or mistakes that prevented it from working the first time.&lt;/p&gt;
&lt;p&gt;Still, they were valuable: When I asked it to solve &lt;a href=&quot;https://en.wikipedia.org/wiki/Eight_queens_puzzle&quot;&gt;the N-Queens problem&lt;/a&gt; it produced a broken version with errors, but the errors were quite minor and I fixed them within 15 minutes. Once they were solved, the program worked perfectly. It would have taken me well over an hour to solve, so there was a clear and obvious benefit to using the tool even if it did not produce perfect results on the first try. I also shared my fixed version with the bot to see if it would learn from it and when I later asked it to solve N-Queens again some of the errors I’d pointed out were now absent, but not all of them.&lt;/p&gt;
&lt;h2 id=&quot;but-what-about-tests&quot;&gt;But what about tests&lt;/h2&gt;
&lt;p&gt;Of course, as an advocate of TDD, it would be a major oversight to only look at production code. Well, the good news is ChatGPT can write tests. When asked to write a test for the function it wrote above, it produced this:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;#[test]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; test_move_rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Define a test case with a set of commands and the expected final position of the rover.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; test_cases&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; [        (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;MMRMMLM&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)),        (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;MMMMMMMMMM&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)),        (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;LMLMLMLMM&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)),        (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;RMRML&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)),        (&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;MMMMMLLLRLRM&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)),    ];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Iterate over the test cases and check that the `move_rover` function produces the expected output.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; &amp;amp;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;commands&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; test_cases&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;iter&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; rover&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;N&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;        move_rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;commands&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;        assert_eq!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.x, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.y, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;rover&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.direction), (&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;direction&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is once again surprisingly advanced: It is using test cases to write 6 tests for the price of one. However, most of the tests didn’t pass. The test logic is written correctly, but the test cases themselves are invalid: In one case it expects &lt;code&gt;MMMMMLLLRLRM&lt;/code&gt; to result in &lt;code&gt;(0, 0, &apos;E&apos;)&lt;/code&gt; but the correct result is &lt;code&gt;(0, 5, &apos;S&apos;)&lt;/code&gt;. The implementation produces the correct result too, so the incorrect test fails. Once again, ChatGPT has no way of verifying this itself: It is effectively guessing as to what will work. Mistakes like these highlight the major drawbacks of applying it as a tool for software engineering: It is excellent at producing something that &lt;em&gt;looks&lt;/em&gt; correct, but it cannot understand the actual logic to ensure that it is correct.&lt;/p&gt;
&lt;p&gt;Also of interest was another test I performed to examine if it can generate implementation from tests. I used an &lt;a href=&quot;https://exercism.org/&quot;&gt;Exercism&lt;/a&gt; exercise, for which all the tests are provided but not the implementation. Omitting the description of the problem I copied just the test definitions into ChatGPT and asked it to write a function that would make them pass. It did remarkably well: Despite not having the description it inferred exactly what the problem was from test names, variable names, and the assertions and wrote a function that compiled the first time and passed half the tests. Not quite a passing mark, but far better than any other tool I am aware of.&lt;/p&gt;
&lt;h2 id=&quot;but-what-about-software-design&quot;&gt;But what about software design&lt;/h2&gt;
&lt;p&gt;But can it produce code that is well-encapsulated, readable, and follows SOLID? Can it understand design principles? In the session with my colleagues, we tested this with &lt;a href=&quot;https://www.c-sharpcorner.com/article/solid-with-simple-example/&quot;&gt;an example from CSharpCorner&lt;/a&gt;. We asked it what problem does it see with this code:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Customer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        try&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;            db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        catch&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;            File&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;WriteAllText&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;@&quot;C:\Error.txt&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It came up with three problems, all very well explained, and demonstrated how to fix them in the code. But these problems are all related to implementation details, to how the try-catch in this example is not typing the error correctly or understanding it well. It also seemed convinced that it was best practice to always re-throw an error after logging it, which I am dubious about. Anyway, this was not what we were looking for so we tried a different question: “What would you do to make the following code follow the Single Responsibility principle?” This time, it gave the following quite compelling response:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Customer class in this code appears to have two responsibilities: adding a customer to a database and logging any exceptions that occur. To make the code follow the Single Responsibility Principle, you could split these responsibilities into two separate classes. Here is an example of how you could do that:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Customer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;        db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; ExceptionLogger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Log&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;        File&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;WriteAllText&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;@&quot;C:\Error.txt&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;ToString&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;In this code, the Customer class only has a single responsibility, which is to add a customer to a database. The ExceptionLogger class has a single responsibility, which is to log exceptions to a file. This separation of responsibilities can make the code easier to understand, maintain, and extend.
To use these classes, you could catch any exceptions that occur in the Customer class and pass them to the ExceptionLogger class to be logged. Here is an example of how you could do that:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Customer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Database&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        try&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;            db&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        catch&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Exception&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;            var&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; logger&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; new &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;ExceptionLogger&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;            logger&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Log&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;ex&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;In this code, the Add method catches any exceptions that occur when adding a customer to the database and passes the exception to the &lt;code&gt;ExceptionLogger&lt;/code&gt; class to be logged. This approach follows the Single Responsibility principle by keeping the code for adding a customer and the code for logging exceptions separate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This time, with a hint, it has picked up on exactly what the CSharpCorner article was getting at with this example. And seemingly explained it quite well, too. As a bonus, it is also using C#‘s convention of capitalising function names which is interesting because we forgot to specify that the code was in C#. It has inferred as such from the code itself, despite being so similar to Java.&lt;/p&gt;
&lt;p&gt;If we have to ask it such a leading question to get this result then the practical uses for software design may be limited, but it does at least demonstrate an understanding of some software design principles. Next, we tried testing whether it can apply design patterns, by asking it to apply the repository pattern to this sample:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To apply the repository pattern to the code in the previous example, you could create a &lt;code&gt;CustomerRepository&lt;/code&gt; class that handles the data persistence for the &lt;code&gt;Customer&lt;/code&gt; class. The &lt;code&gt;Customer&lt;/code&gt; class would then be able to call methods on the &lt;code&gt;CustomerRepository&lt;/code&gt; class to add and retrieve customers from the database, without having to worry about the details of how the data is stored or accessed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Customer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; readonly&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; CustomerRepository&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; repository&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Customer&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;CustomerRepository&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; repository&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;repository&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; repository&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;        repository&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; CustomerRepository&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    void&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; Add&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Customer&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; customer&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;        // Code to add the customer to the database&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;In this code, the &lt;code&gt;Customer&lt;/code&gt; class has a reference to a &lt;code&gt;CustomerRepository&lt;/code&gt; object, which it uses to add and retrieve customers from the database. The &lt;code&gt;CustomerRepository&lt;/code&gt; class contains the code for managing data persistence, including adding customers to the database. This separation of concerns allows the Customer class to focus on implementing business logic without worrying about data persistence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It has pulled this off too. It even explains some of the reasoning and benefits of this practice, some of which I’ve omitted for brevity. It is a bit odd that it places the repository inside the &lt;code&gt;Customer&lt;/code&gt; class, it is a bit off to make a class dependent on a class designed to store it but within the context of this question, it makes sense, as our example included the &lt;code&gt;Add&lt;/code&gt; function. It has done what we asked it to.&lt;/p&gt;
&lt;h2 id=&quot;other-interesting-uses&quot;&gt;Other interesting uses&lt;/h2&gt;
&lt;p&gt;Beyond writing production code, tests, and applying software design principles to transform code there are a few other interesting use cases for ChatGPT within the software domain.&lt;/p&gt;
&lt;h3 id=&quot;a-smart-search-engine&quot;&gt;A Smart Search Engine&lt;/h3&gt;
&lt;p&gt;ChatGPT can effectively act as a plain language search engine for quite complex queries. I’ve found it is capable of explaining complex concepts like the Rust ownership and borrowing rules effectively, and even correctly answering oddly specific questions like “What is the default port of a new MySQL database?”. In my experience, it is often faster and easier to ask ChatGPT in plain language than to apply your google-fu to try to discern the right incantation of search keywords that will bring up the result you need. You can’t necessarily be confident in the answers it provides, though. More on that later.&lt;/p&gt;
&lt;h3 id=&quot;translate-this-error-message-please&quot;&gt;Translate this error message, please&lt;/h3&gt;
&lt;p&gt;One novel use I’ve found is to give ChatGPT an error message and ask it to explain to me what is happening in simple terms. I asked it to explain to me &lt;a href=&quot;https://todon.eu/@mattsi/109410387258761414&quot;&gt;a quite complex Rust lifetimes error&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;79 |    pub fn make_move_mut(&amp;amp;mut self, requested_move: &amp;amp;Move) -&amp;gt; (Game,Option&amp;lt;ResolvedMoveMemento&amp;gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |                         -                          - let&apos;s call the lifetime of this reference `&apos;1`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |                         |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |                         let&apos;s call the lifetime of this reference `&apos;2`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |         (self.determine_status(), Some(memento))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `&apos;2` but it is returning data with lifetime `&apos;1`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Though the Rust compiler already does a much better job than any other compiler I know when it comes to clear error messages,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Rust compiler is indicating that the function &lt;code&gt;make_move_mut&lt;/code&gt; is returning a tuple containing a reference of lifetime &lt;code&gt;&apos;1&lt;/code&gt; and an &lt;code&gt;Option&lt;/code&gt; containing a value of type &lt;code&gt;ResolvedMoveMemento&lt;/code&gt; with a lifetime of &lt;code&gt;2&lt;/code&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;To fix this error, the lifetime of the reference and the value inside the &lt;code&gt;Option&lt;/code&gt; must be made explicit in the function’s return type. This can be done by using a lifetime parameter &lt;code&gt;&apos;a&lt;/code&gt; in the return type, and then specifying that &lt;code&gt;&apos;a&lt;/code&gt; is the same as the lifetime of &lt;code&gt;self&lt;/code&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is an example of how the fixed function signiature might look:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pub fn make_move_mut&amp;lt;&apos;a&amp;gt;(&amp;amp;&apos;a mut self, requested_move: &amp;amp;Move) -&amp;gt; (Game&amp;lt;&apos;a&amp;gt;, Option&amp;lt;ResolvedMoveMemento&amp;lt;&apos;a&amp;gt;&amp;gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  (self.determine_status(), Some(memento))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;… This tells the Rust compiler that the reference and the value inside the &lt;code&gt;Option&lt;/code&gt; have the same lifetime, which is the same as the lifetime of &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ve omitted a lot again here, but it was a really interesting response and helpful. I’m not sure that its suggested solution is quite correct - I don’t believe I’ve seen anyone apply a Rust lifetime to the &lt;code&gt;self&lt;/code&gt; argument before, but it does seem to work in my tests. But in any case, it again demonstrates impressive competency.&lt;/p&gt;
&lt;h2 id=&quot;convert-code-from-one-language-to-another&quot;&gt;Convert code from one language to another&lt;/h2&gt;
&lt;p&gt;Another interesting use is converting code. Separation of content and format comes naturally to a language model like ChatGPT - you can even ask it to convert a document into a screenplay, then to a limerick, to a poem, to a song, etc. Similarly, you can tell it “convert this function to Python” and it will give you pretty good results in my experience.&lt;/p&gt;
&lt;h2 id=&quot;querying-datasets&quot;&gt;Querying datasets&lt;/h2&gt;
&lt;p&gt;This was a novel use case I hadn’t considered until a colleague of mine suggested it. Paste in a dataset in JSON, XML, or some such format and ask it a question like “What is John Smith’s date of birth”. It will parse the dataset, find John Smith, and give you that value. It even shows you exactly where in the structure of the document that information can be found. Querying documents in natural language, What a wonderful way to be lazy.&lt;/p&gt;
&lt;p&gt;More impressive still I found that I could ask it to write a &lt;a href=&quot;https://stedolan.github.io/jq/&quot;&gt;JQ query&lt;/a&gt; to find that information, and it generated one perfectly (plus explaining how the query works). In theory, if you want to apply some transformation to a large dataset with many nested values you could use ChatGPT to query for the data in natural language, and then provide a query your computer can understand to be used in automated scripts over that dataset. Very cool.&lt;/p&gt;
&lt;h2 id=&quot;limitations&quot;&gt;Limitations&lt;/h2&gt;
&lt;p&gt;Okay, ChatGPT can do some radical things. Why are so many people cynical about it? What are the problems we must temper our excitement with?&lt;/p&gt;
&lt;h3 id=&quot;dont-believe-its-lies&quot;&gt;Don’t Believe It’s Lies&lt;/h3&gt;
&lt;p&gt;The biggest limitation is that &lt;strong&gt;ChatGPT cannot verify the information it provides&lt;/strong&gt;. Just as it cannot compile code, it similarly cannot test the veracity of any of the information it has read and willingly repeats. Yet, it is perfectly confident. It has no “I think this is right but I’m not sure” behaviour: It will either not be able to answer, or it will give you an answer with perfect confidence that might be completely wrong. Adam Shaylor wrote &lt;a href=&quot;https://adamshaylor.svbtle.com/chatgpt-and-the-viability-of-replacing-humans&quot;&gt;a really interesting take&lt;/a&gt; on this issue: in his tests, ChatGPT seemed to produce interesting and clever results, until you look closer and realise that some of its answers are nonsense presented as fact. There is something about the way it speaks that seems to exude confidence and correctness, and trick you into thinking that it is cleverer than it is. And that should not be surprising: This whole thing is essentially a machine learning program that has been trained to trick you into thinking it is intelligent. Machine learning algorithms are good at finding niche, unexpected ways of hacking at a problem: Has ChatGPT found exactly the right type of language, writing style, and vocabulary to trick us into thinking of it as correct? Has it found some loophole in how our brains and/or language work that we don’t fully understand?&lt;/p&gt;
&lt;p&gt;On the other hand, what is the difference between tricking someone into thinking you are intelligent and really being intelligent? If the end result is the same, then what does it matter? Well, the problem is that the end result is the same maybe 9/10ths of the time. And that 1/10th of the time that it is wrong can be difficult to recognise because ChatGPT will be just as confident in its answer as the other 9/10 times. So, any use of this technology has to be carefully verified: We cannot apply blanket trust to this thing, as much as it may try to convince us that we can.&lt;/p&gt;
&lt;h3 id=&quot;internet-not-included&quot;&gt;Internet Not Included&lt;/h3&gt;
&lt;p&gt;As a machine learning model, ChatGPT has no access to information it was not trained on. It cannot access the internet to learn new information. As new versions of compilers, syntax, protocols, etc are published in the future this model will not be aware of any of the changes they bring. The model may well get updated in the future, but it will almost always be at least somewhat out of date. Even now it is only trained up to 2021, so it is not aware of newer Rust features for example like Generic Associated Types (GATs). In fact, when I asked about GATs it provided me with a very believable-looking answer that explained what associated types were and what generics were and sorta mish-mashed them together but completely missed what a GAT was. If I hadn’t been researching GATs myself lately, I might have believed it.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-shoot-myself-in-the-foot&quot;&gt;How do I shoot myself in the foot?&lt;/h3&gt;
&lt;p&gt;Another major restriction is that ChatGPT will do exactly what you ask: It does not consider context or circumstance. If you, proverbially, ask it how to shoot yourself in the foot it would reply “To shoot yourself in your foot, first take a Glock-18 and a 9mm bullet…”. This problem is a big part of the argument for why it has been banned from StackOverflow. During our session my colleagues and I found a good example of exactly this behaviour, when we, first of all, asked it to produce a solution to FizzBuzz which came out like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;..=&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;            println!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;FizzBuzz&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;            println!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;Fizz&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; % &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;            println!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;Buzz&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;            println!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;{}&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then we asked it to generate a unit test for that function, which came out like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;#[test]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt; test_fizzbuzz&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Capture the output of the main function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; Vec&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; out&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Cursor&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; result&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;BufWriter&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;buffer_len&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; out&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;io&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;BufWriter&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;with_capacity&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;out&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;        main&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;mut&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; out&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Convert the output to a string and split it into lines&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;from_utf8&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#E5C07B&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;\n&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&apos;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;collect&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt;    // Check that the first 15 lines of output are correct&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;    assert_eq!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;    assert_eq!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;2&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;    assert_eq!&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;], &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;Fizz&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can you see the issue? The original function was written in a way that cannot easily be tested because there is no abstraction around &lt;code&gt;println!&lt;/code&gt;. Instead of trying to solve this problem by refactoring the original function, ChatGPT has done precisely what we asked: It tried its best to test the untestable function, by writing a bonkers test that tries to capture everything the main function prints. I’m not sure how exactly to do this in Rust, but the solution ChatGPT provided does not work though the intention at least is clear.&lt;/p&gt;
&lt;h3 id=&quot;does-it-really-save-time&quot;&gt;Does it really save time?&lt;/h3&gt;
&lt;p&gt;We are professionals. It is totally out of the question to blindly push code that ChatGPT has written to our clients’ repositories. As we have seen, ChatGPT cannot be trusted to produce correct results. As such, every last piece of output it produces must be carefully read over and checked and double-checked if we are to seriously use it. But if that is the case, is using ChatGPT really any faster than writing it ourselves? How long would it take to read, check, re-check and be fully confident in a solution ChatGPT has written versus just writing it ourselves?&lt;/p&gt;
&lt;p&gt;I don’t know yet what the answer is. Perhaps further experimentation is required.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In 10 years’ time, we may be using tools like this every day. I can imagine sitting in front of my IDE, telling it “Okay, now add a repository to save that record to the database” and then reviewing the code it’s written, fixing some things here and there. It could really save time and make our lives easier. Software development has always grown more abstract as we develop better techniques: Languages like C made our lives easier by introducing a shared cross-platform language, and more expressive code that could do more with fewer lines. Then came garbage collection in languages like Java and C#, removing whole swathes of concerns from day-to-day development. We even have cloud providers and Terraform to abstract away the hardware. Perhaps this will be another development in the same direction: Instead of writing quite as much code, you describe what you want to achieve in software design terms, then review and adapt the first-pass template that your IDE will generate for you.&lt;/p&gt;
&lt;p&gt;Of course, we must never let tools like this replace our responsibility to produce safe, readable, high-quality code. One thing I’m worried about is this: There are so many developers out there that are bad at writing tests. Often they don’t understand testing but their employers are desperate for more tests to comply with some regulation or meet an arbitrary amount of code coverage that a contract requires. One of these developers will get the bright idea to let a language model write their tests for them with minimal or no oversight. &lt;strong&gt;This is a dreadful idea with awful implications&lt;/strong&gt;, but I guarantee you someone will do it. All the ingredients for mistakes like this exist in our industry, and the motivations are particularly strong in organisations running safety-critical systems.&lt;/p&gt;
&lt;p&gt;So, can ChatGPT write code? Yes. Should you use it as such? Maybe, but only with extensive oversight of everything it writes. Will more tools arrive in the coming years that make ChatGPT look like child’s play? Yes, almost certainly.&lt;/p&gt;</content:encoded></item><item><title>Retrospective - London Global Day of Code Retreat 2022</title><link>https://www.matt.si/2022-12/code-retreat/</link><guid isPermaLink="true">https://www.matt.si/2022-12/code-retreat/</guid><description>I ran London&apos;s Global Day of Code Retreat meetup at Codurance. Find out more about Global Day of Code Retreat and how the event went</description><pubDate>Sun, 11 Dec 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;First posted on &lt;a href=&quot;https://www.codurance.com/publications/coderetreat-london-2022&quot;&gt;the Codurance Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Global Day of Code Retreat is an annual in-person event that takes place in numerous cities across the globe. Each event has the same purpose: Get a load of programmers together in the same room to practice pair programming and TDD. You get to learn from and teach people, practice programming patterns you haven’t tried before, and network with your peers from across the industry. This year I facilitated the London event with LSCC, the London Software Craftsmanship Community. Jetbrains sponsored the event with a free license to any Jetbrains IDE, and Codurance sponsored the location and food.&lt;/p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The Code&lt;/h2&gt;
&lt;p&gt;Coderetreat focuses on one particular programming challenge: Conway’s Game of Life. Game of Life is a fun little simulation to implement, it can be confusing at first to people that haven’t studied it before but if you know the problem well you can easily implement it in under an hour. However, the point is not to code Game of Life. Completing the challenge is not the aim. The goal is the experience and learnings from pairing with your peers and trying new things. In particular, practicing or learning (it was a first for most of our attendees!) TDD and pair programming.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/FdMzngWchDk&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;the-structure&quot;&gt;The Structure&lt;/h2&gt;
&lt;p&gt;The day consists of five sessions of pairing with someone new each time, for about an hour each. In each session you spend 45 minutes programming and 15 minutes on a retrospective discussing what you learned or what you found interesting in that session, or simply showing off a particular implementation that you are proud of. After each session you delete your code (Because again, coding is not the point - the expderience is!). You may be surprised how many different ways the simple rules of Conway’s Game of Life can be implemented. And pairing with someone different each time enables you to get out of your own typical ways of coding and see how other people outside of your bubble look at a problem.&lt;/p&gt;
&lt;p&gt;But if you get bored of doing the same problem repeatedly, you can switch it up with &lt;a href=&quot;https://www.coderetreat.org/facilitators/constraints/&quot;&gt;constraints&lt;/a&gt;. Constraints throw a wrench in your usual way of coding to see if you can learn something by doing things differently. Some of them are quite funny ones like not using an IDE or even writing all your code on paper. Others are interesting ways of working together such as ping-ponging, in which you switch which one person writes the tests then you switch and the other makes the test pass. There are also a lot of interesting software design constraints that I think one can really learn a lot from such as never using primitives, or only having one level of indentation, never using mutable variables.&lt;/p&gt;
&lt;h2 id=&quot;the-day&quot;&gt;The Day&lt;/h2&gt;
&lt;p&gt;The day went very smoothly. Quite a few people were new to TDD and pair programming so it was really interesting to see their experience and their reactions. It lead to a lot of interesting conversation as to their experiences and the value of these practices. It was really interesting to see people getting up to speed throughout the day, too: In the first two sessions a lot of people struggled to get one passing test, but by the end of the day most pairs were getting substantially far through the challenge in just 45 minutes and we had several pairs that managed to complete it.&lt;/p&gt;
&lt;p&gt;For those struggling to get the hang of it I shared an example of &lt;a href=&quot;https://github.com/Steelstone3/Rust-Study-Group/blob/multithread-team-mpjj/src/lib.rs&quot;&gt;a solution written in Rust&lt;/a&gt; that some friends and I had made and going through that during one of the retrospectives seemed to help. We also found that many people were finding it difficult to get started due to difficulty with setting up new projects, installing and configuring the right test framework or getting tests to run. This is something everyone got better at as the day went on but we also suggested &lt;a href=&quot;https://github.com/remote-code-retreat/code-retreat-2019/tree/master/presets&quot;&gt;Code Retreat’s starter repo&lt;/a&gt; as a faster way to get started, and that seemed to help some pairs.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2022-12/code-retreat/coderetreat-room.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2022-12/code-retreat/coderetreat-room.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt; 
&lt;p&gt;We’ve also asked some of the attendees to share their experiences of the day. Robert Firek had this to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Not my first time, and probably not the last one. As usual, I enjoyed seeing how the same problem can be solved in so many different ways. Especially, I could share my experience. Great to see that so many people are still happy to meet and learn something new&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Chris Eyre from &lt;a href=&quot;https://www.prima.it/&quot;&gt;Prima&lt;/a&gt; shared this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I paired with 5 different people each with a varied level of experience. 4 of the attempts I used Elixir and one in Python. It’s a great way to work with a range of people that you would not normally meet. I would recommend this to anyone getting into TDD (or if you are already into TDD and want to share).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Magda Firek who started her programming journey earlier this year shared this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was the first workshop of this type that I participated in. It is also the first time I have dealt with the TDD technique, and I can say right away that I will use it in the future. Connecting with programmers who code in different languages was very interesting. I’ll join next year for sure to see how my knowledge improved. Massive “Thanks” to Codurance for organising.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-end&quot;&gt;The End&lt;/h2&gt;
&lt;p&gt;So, that was Global Day of Code Retreat 2022. If you think this sounds awesome, join us at Code Retreat 2023 next year! But you don’t have to wait until then, London Software Craftsmanship will be hosting &lt;a href=&quot;https://www.meetup.com/london-software-craftsmanship/&quot;&gt;lots of other regular events in-person in London before then&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>Rust Macros - The What, Why and How</title><link>https://www.matt.si/2022-05/macros-what-why-how/</link><guid isPermaLink="true">https://www.matt.si/2022-05/macros-what-why-how/</guid><description>I delivered a &quot;Thursdays Matter&quot; talk with SkillsMatter about Rust macros; what they are, why to use them and how they work.</description><pubDate>Thu, 26 May 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I delivered a “Thursdays Matter” talk with SkillsMatter about Rust macros; what they are, why to use them and how they work.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/zeCdNPeU40A&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;encrypted-media; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title>Introduction to Rust</title><link>https://www.matt.si/2022-04/intro-to-rust-talk/</link><guid isPermaLink="true">https://www.matt.si/2022-04/intro-to-rust-talk/</guid><description>At Codebar 2022 I gave a talk introducing newcomers to the Rust programming language. It covers what Rust is, why you might want to use it and where to go to learn more.</description><pubDate>Thu, 21 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At codebar festival 2022 I gave a talk introducing newcomers to the Rust programming language. It covers what Rust is, why you might want to use it and where to go to learn more.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/6FnOiIW7LB8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;encrypted-media; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;</content:encoded></item><item><title>Want to learn a new skill? Start a study group, here&apos;s how</title><link>https://www.matt.si/2021-05/study-group/</link><guid isPermaLink="true">https://www.matt.si/2021-05/study-group/</guid><description>The story of how I began learning a new programming language by starting a study group, and you can too</description><pubDate>Mon, 17 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hoping to broaden my programming horizons in 2020 I studied F#, but I didn’t make as much progress as I’d hoped. My objective in 2021 is to pick up Rust, and I wanted to try something different this time. Thinking back to a study group I’d been part of in the past, and to group projects and such in my student days, I saw the following advantages to study groups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Goals and deadlines - a group has to move to some cadence that is agreed up-front by all involved. Something like “Let’s read a chapter every week”. This gives you a specific, measurable goal and a timeframe to complete it in.&lt;/li&gt;
&lt;li&gt;Motivation - I find that it is easy to put off something if you’re doing it for yourself. But if you’re doing it for someone else? In my experience that is much more motivating. Studying together involves making commitments to keep up with the reading pace and to prepare material for a study session, so you get that extrinsic motivation.&lt;/li&gt;
&lt;li&gt;Feedback - once you’ve read and practised some particular aspect of what you’re trying to learn, how do you know you’ve understood it correctly? In a group setting you can share your understanding with one another and get feedback on whether you’ve understood the material correctly.&lt;/li&gt;
&lt;li&gt;Fun - it is much more fun to learn along with friends and colleagues than to slog away by yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, based on that I started a study group in January. We meet every other week, regularly get 5-7 people in attendance, read &lt;a href=&quot;https://doc.rust-lang.org/book/&quot;&gt;The Rust Book&lt;/a&gt; and have fun while we’re at it. It has been great- I feel I’ve easily learned as much about Rust after a few months as I did about F# in all of 2020. So if you have something you want to learn- any kind of skill or knowledge- I suggest looking for others who are interested in it too, from your workplace and among your friends, and studying together.&lt;/p&gt;
&lt;h2 id=&quot;how&quot;&gt;How&lt;/h2&gt;
&lt;p&gt;Okay that was the “why”, here is the “how”. The first thing is to create a channel or group chat (in Slack, Teams, Discord, or whatever application). You’ll need this space to coordinate together. Then drop some messages about what you want to study and the name of the channel into several prominent, related channels/group chats. Don’t be shy, make sure as many see it as possible. In my case I dropped my message in several of the most populated channels in my work Slack but still had people only finding out about it and joining over a month after we’d started.&lt;/p&gt;
&lt;p&gt;It is important to create your channel first, because it gives anyone that’s interested a place to register their interest and host discussions- otherwise you have several disjointed discussions in different channels. In my case I didn’t create the channel until later and exactly that happened.&lt;/p&gt;
&lt;p&gt;Lastly, you want to big it up in meetings and water cooler chats with friends and colleagues too. Not everyone watches group chats like a hawk, but word of mouth may reach them.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2021-05/study-group/slack-message.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2021-05/study-group/slack-message.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;A modestly successful first message&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Then I’d suggest you invite anyone that showed an interest, give it a little time to see who joins, and start openly discussing how this group might work. In my case I made it clear from the start that I didn’t intend to dictate how this would work. I think that helped to get people engaged and invested in the group. I did this by asking for input from the group on every decision and taking votes (posting the options and voting with emoji reacts works well). There are a bunch of things you should decide together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How often will we meet? I found every other week works well&lt;/li&gt;
&lt;li&gt;What day &amp;amp; time will we meet? It should be a time that works for as many people as possible, but at the same time you can’t please everyone.&lt;/li&gt;
&lt;li&gt;What will we study? There are probably numerous resources on your subject, and you need to agree on one shared goal.&lt;/li&gt;
&lt;li&gt;What will the format be?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;format&quot;&gt;Format&lt;/h3&gt;
&lt;p&gt;That last one, the format, is important. You should agree on the format between yourselves and even iterate on it as need be in the future, but let me offer the format we’ve settled on as a template. I’m not sure of the exact origin of this format, but it’s based on something my colleague &lt;a href=&quot;https://twitter.com/alfredodev&quot;&gt;Alfredo&lt;/a&gt; suggested in a previous study group. The format goes like this, chronologically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Greetings/chatting&lt;/li&gt;
&lt;li&gt;Ask who’s completed the reading, find out where we all got to and how we found it.&lt;/li&gt;
&lt;li&gt;For each section of reading we’ve completed since the last meeting someone makes a presentation
&lt;ul&gt;
&lt;li&gt;This can take any form- slides, a live coding demo, a conversation. It’s worth discussing with your group which presentation styles work for them and keep that in mind, but there’s no need to be prescriptive.&lt;/li&gt;
&lt;li&gt;Everyone should feel free to interrupt and discuss. The presenter should put their understanding of the material up for scrutiny. The ensuing discussion challenges any misunderstandings that we may have unwittingly picked up and ensures everyone has the same shared understanding.&lt;/li&gt;
&lt;li&gt;Presentations can be interactive- I find that throwing in a &lt;a href=&quot;https://kahoot.com/&quot;&gt;Kahoot&lt;/a&gt; quiz works great.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discuss any exercises we’ve completed since the last meeting- what was challenging or confusing, how did you find it?
&lt;ul&gt;
&lt;li&gt;In our case we use the &lt;a href=&quot;https://github.com/rust-lang/rustlings&quot;&gt;Rustlings code exercises&lt;/a&gt; and &lt;a href=&quot;https://exercism.io/tracks/rust&quot;&gt;Exercism Rust track&lt;/a&gt; to practice between meetings. Each of the Rustling exercises are mapped to chapters in the book, so we can ensure they’re relevant to what we’re reading.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decide how much of the material we’ll commit to reading before the next meeting
&lt;ul&gt;
&lt;li&gt;The word “commit” here is key- this is something you’re all committing to completing within a timeframe, so don’t be overambitious. Ensure it is something that everyone is comfortable with.&lt;/li&gt;
&lt;li&gt;We look up the page numbers of the next few chapters so that we know how long they are, then compare that to how many pages we got through in previous iterations.&lt;/li&gt;
&lt;li&gt;If, based on the previous exercise, we don’t think we can complete the next whole chapter then we’ll split it into smaller sections.
&lt;ul&gt;
&lt;li&gt;Estimating and splitting work, informing planning by how much we completed in previous “sprints” - you may notice that this is similar to how agile planning works. I suppose the same principles apply everywhere.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Decide which exercises we’ll commit to completing before the next meeting
&lt;ul&gt;
&lt;li&gt;As above, but with exercises (in our case, coding challenges. But it could be sheet music to play, or foreign language books to read, or whatever).&lt;/li&gt;
&lt;li&gt;Ideally these should be relevant to the material. In our case this was easy because the Rustling exercises map to the chapters in the book.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Ask for volunteers to present at the next meeting
&lt;ul&gt;
&lt;li&gt;They will prepare a presentation of some sort to share their notes and thoughts on some section of the material for the next meeting.&lt;/li&gt;
&lt;li&gt;These make up the presentations (as we saw at the start of the format) for the next session.&lt;/li&gt;
&lt;li&gt;Split the material into sections however you like- we often split long chapters into two separate presentations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lastly, feel free to switch up the format on occasion. This keeps it fresh and less repetitive. In my case after we’d read the first 10 chapters of The Rust Book I recommended doing a &lt;a href=&quot;https://codingdojo.org/WhatIsCodingDojo/&quot;&gt;coding dojo&lt;/a&gt; session, to apply our new skills practically with some pair-programming. The rest of the group was keen and the session was really fun and helpful, and switching up the format helped to keep the group from feeling repetitive or stale.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I really recommend this approach, it has worked great for me. If you try it, let me know how you get on. And if you know any other study group formats let me know, I’d love to try some new ones out.&lt;/p&gt;</content:encoded></item><item><title>Book Review- &quot;You First; Inspire Your Team…&quot; by Liane Davey</title><link>https://www.matt.si/2020-01/you-first-review/</link><guid isPermaLink="true">https://www.matt.si/2020-01/you-first-review/</guid><description>A review of Liane Davey&apos;s book &quot;You First; Inspire Your Team to Grow Up, Get Along, and Get Stuff Done&quot;</description><pubDate>Thu, 30 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;My reading material throughout most of December was You First by Liane Davey, a book about dysfunctional teams and how to not be part of their problem. Davey establishes the term “Toxic Team” to model teams where “the lack of alignment and the poor dynamic are a threat to both the productivity of the organization and the engagement and well-being of individual members”; in other words, teams whose members don’t get along and/or can’t work together frictionlessly to the point that it harms the team. I very much appreciate the “well-being of individual members” part; Davey approaches this problem not just as an obstacle to the organisation’s productivity, but to the quality of life and health of the inviduals in the team.&lt;/p&gt;
&lt;p&gt;Davey models these toxic teams as having distinct types;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Crisis Junkies: a team that has to be constantly fighting fires, and otherwise isn’t productive.&lt;/li&gt;
&lt;li&gt;Bobble Heads: a team that never disagrees with or criticises their leaders&lt;/li&gt;
&lt;li&gt;Spectators: an apathetic team wherein no-one presents alternative ideas&lt;/li&gt;
&lt;li&gt;Bleeding Back: a team where trust has broken down, but members act happy in public and take out their frustrations in back-channel, private discussions.&lt;/li&gt;
&lt;li&gt;Royal Rumble: a team that can’t come to a consensus, wherein members commit viscious personal attacks against one another rather than having an objective debate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first half of the book details the model that Davey has established after years of experience business consulting, and during her PhD at University of Waterloo in Industrial/Organizational Psychology. The second half introduces positive behaviours one can use to reform a toxic team. One of the central promises of the book is that by exhibiting these positive behaviours just one person can turn a team around. This second half of the book I found to be much more interesting than the first, it’s very self-reflective; Davey ernestly encourages you to take a long hard look in the mirror and ask yourself what you can do better. It’s a kind of tough love that she espouses like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All I can do is hold up the mirror. You have to do the rest. If you really let the words sink in, some of them may be tough to hear… But if you’re willing to go there, you’ll find it’s liberating to understand why you are acting the way you are. If you’re behaving badly, it’s probably not because you want to. It’s more likely that you started using a coping mechanism to survive during a particularly hectic or vulnerable time. Taking a shortcut helped you to survive, but now you’re seeing the negative effects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;insights&quot;&gt;Insights&lt;/h2&gt;
&lt;h3 id=&quot;amplifying-other-voices&quot;&gt;Amplifying Other Voices&lt;/h3&gt;
&lt;p&gt;One part of the book discusses “Amplifying Other Voices” and I felt it was very relevant to Software Engineering. Davey discusses a team in which every member was a blue-sky thinking, big ideas person except for one. This lone, process-minded pragmatist found themselves ostracised from the team and had to work hard to make their point of view heard.&lt;/p&gt;
&lt;p&gt;Unfortunately this reminds me of how software teams tend to consist mostly of developers, with one or two attaches representing other interests; a Quality Analyst, a Product Owner, maybe a Business Analyst. I’ve often found that a tight-knit culture emerges around the developers with their shared interests (technical excellence, ways of working, prioritising technical debt) while non-developers may have other motivations (Timely delivery, pressure from upper management, user experience). If your team has this problem particularly badly you may catch yourself referring to people in these roles as “The business”; as in “We should see what The Business thinks of this; let’s ask Dave”, as if the developers weren’t part of the business at all.&lt;/p&gt;
&lt;p&gt;Davey suggests that we can solve these problems by amplifying other voices. Not that we need be guilty about the blitheness that occurs when you get a bunch of computer nerds in the same room, but that we should be &lt;em&gt;aware&lt;/em&gt; of how a boisterous group may inadvertently drown out the minority, that our perspective &lt;em&gt;isn’t&lt;/em&gt; the only valid one and that to achieve a measure of balance we need to &lt;em&gt;amplify&lt;/em&gt; the minority’s voice before we can have a diverse discussion that appreciates every angle.&lt;/p&gt;
&lt;h3 id=&quot;start-with-a-positive-assumption&quot;&gt;Start with a Positive Assumption&lt;/h3&gt;
&lt;p&gt;I’m a bit of a cynic. I don’t trust people easily, and I’ll often second-guess what another person’s motivations may be. So this is the chapter that spoke to me the most. In it Davey suggests a simple principle to live by; start with a positive assumption. Anyone you have dealings with, assume that what they say is in ernest, that they’re committed to their work and have no ill intentions.&lt;/p&gt;
&lt;p&gt;Davey describes four areas of trust: connection, competence, reliability, and integrity. In this context, I’m a little confused as to what “connection” means; but Davey uses it to say that you should assume everyone you meet is “a decent human being who got up in the morning and came to work to do a good job and make a contribution”. The other three are self-explanatory, but I particularly like Davey’s reasoning for why we should trust one another’s integrity:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you sit across the table from someone assuming that they are going to screw you, you are actually giving them a reason to do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Davey suggests that we can change our behaviour by &lt;em&gt;stifling the impulse&lt;/em&gt; to make a cynical assumption, &lt;em&gt;consider the context&lt;/em&gt; that this person sees the topic from, &lt;em&gt;get more information&lt;/em&gt; by asking open-ended questions, and &lt;em&gt;listen for clues&lt;/em&gt;: try to understand the underlying emotions and beliefs that may have informed the other person’s perspective, and look for any evidence they may have that contradicts your own view. This method reminds me very much of critical thinking; go out of your way to expose yourself to contradicting views, and ernestly analyse their merit. Don’t trust your own assumptions, but rather accept your falibility and practice self-correction.&lt;/p&gt;
&lt;p&gt;Since reading You First this phrase, “Start with a Positive Assumption”, has been rattling around in my head. Whenever I find myself questioning someone’s intentions, I remind myself to start with a positive assumption. By coincidence when I was attending &lt;a href=&quot;https://twitter.com/mattsijansky/status/1223208303729180679&quot;&gt;the Codurance OpenSpace&lt;/a&gt; recently one of my colleagues initiated a round-table discussion on the topic “Assume Good Intentions”, which seems to be the same concept. They described how they’d been practicing it as a mantra of sorts for years until they no longer thought of it at all, and such trust came naturally to them. I hope to reach that point one day, too.&lt;/p&gt;
&lt;h3 id=&quot;overtime&quot;&gt;Overtime&lt;/h3&gt;
&lt;p&gt;I don’t agree with Davey on everything. In particular, we differ on our view of overtime. I feel strongly that overtime should not exist in business. Where overtime is seen it is a symptom that something is wrong (Understaffing, bad deadlines, etc), and by taking part in overtime you mask the problem rather than solve it. You accept being overworked, and the struggling machine continues to maintain it’s mirage of an orderly contraption. Better, I think, to let the machine break and in doing so expose the problems inherent with it.&lt;/p&gt;
&lt;p&gt;I often find my views clash with a pervasive business culture wherein overtime is viewed as a good thing that should be praised. Several times in the book Davey espouses this view, like so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sometimes the inner circles forms among a group of people who work longer hours and go the extra mile. These people have learned to count on one another to get things done when it really matters. Next time a project requires extra hours, roll up your sleeves and find a way to be useful.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case, I would say the “inner circle” is the problem. By letting work take over their lives they’re not only sacraficing their own work-life separation but, as Davey illustrates here, harming other people’s quality of life by creating a growing culture of overtime.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I’ve certainly been on teams that would fit one or more of the book’s definitions of toxic teams, and you probably have too. Perhaps the members of these teams didn’t disagree as violently as the two argumentative foxes in the banner above, but nonetheless there were problems.&lt;/p&gt;
&lt;p&gt;I’ve worked in teams where contentious issues were discussed in secret, where everyone is managing a list of secrets. I’ve worked in teams where colleagues form into cliques that oppose one another. I’ve worked in teams full of apathetic spectators, because management has taught them time and time again that trying to drive positive change is fruitless. Knowing how to handle problems like these effectively is surely part of the professional mastery we should all strive for. So the next time I find myself in a toxic team I’ll reach for Davey’s guide and put it into practice.&lt;/p&gt;</content:encoded></item><item><title>Testing Your Website for Visual Regressions With BackstopJS</title><link>https://www.matt.si/2020-01/backstopjs-tutorial/</link><guid isPermaLink="true">https://www.matt.si/2020-01/backstopjs-tutorial/</guid><description>How to set up BackstopJS visual regression tests and some good practices I&apos;ve picked up from using it in anger</description><pubDate>Sat, 25 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;First posted on &lt;a href=&quot;https://codurance.com/2020/01/16/backstopjs-tutorial/&quot;&gt;the Codurance blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Snapshot testing compares a “snapshot” of the output of a prior version of your software to output from the latest version, to check for unintended changes. When a difference is found you either approve it, by updating the expected output snapshot, or fix the cause of the difference.&lt;/p&gt;
&lt;p&gt;Visual regression testing is a form of snapshot testing that tests a web front-end. It goes beyond testing the markup or layout by testing the rendered page captured in an emulated browser. As such they can “catch CSS Curve Balls” &lt;a href=&quot;https://garris.github.io/BackstopJS/&quot;&gt;as BackstopJS says&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;BackstopJS is a framework for visual regression testing, written in Javascript. It treats your web service as a black box, so your website doesn’t need to be written in Javascript to work with BackstopJS. One of the benefits it offers is a very comprehensive and helpful diff between your snapshots, embedded in a HTML report that it generates. An example below shows how the scrubber diff method allows you to see both test and reference snapshots simultaneously. You can move the red line to change where the boundry lies.&lt;/p&gt;
&lt;p&gt;This article will explain how to set up BackstopJS and some good practices I’ve picked up from using it in anger. You’ll need to have some awareness of Docker Compose and Yarn or NPM.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2020-01/backstopjs-tutorial/backstopjs-scrubber.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2020-01/backstopjs-tutorial/backstopjs-scrubber.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt; 
&lt;h2 id=&quot;why&quot;&gt;Why&lt;/h2&gt;
&lt;p&gt;Why use visual regression testing? I’ll assume that you appreciate why testing as a general practice is necessary, so here are several scenarios that visual regression tests will catch and other testing techniques won’t:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS regressions: Often we’ll make a change to a CSS style to move that one button into the space we’d like it to be, but how do we know that it hasn’t had an undesirable knock-on effect on some other part of the website that uses the same CSS class? Instead of checking every element that may match your CSS selector manually (which we will most often forget to do), run your visual regression tests.&lt;/li&gt;
&lt;li&gt;Responsiveness: Most often we’re working on a 1080p screen, but many (perhaps most) of our users will be using their smartphones. Visual regression tests can test an assortment of different screen sizes, giving you confidence that your changes haven’t broken the responsive page at other sizes and saving you time manually testing the page at different resolutions.&lt;/li&gt;
&lt;li&gt;Dependabot: It’s a wonderful tool that saves you from manually keeping all of your dependencies up-to-date. In my current team &lt;a href=&quot;https://www.codurance.com/publications/2019/02/24/taming-dependabot&quot;&gt;we use dependabot aggressively&lt;/a&gt;; we have extensive testing and auto-merge any Dependabot PRs that pass all our tests. In fact, in terms of PRs or commits it’s the most active member of our team by far. However, you can’t place your trust in Dependabot’s auto-merge in the front-end if you aren’t testing for visual regressions. Before we introduced visual regression testing we had instances where Dependabot would automatically update to a new version of a dependency that introduced a visual change (at one point even removing a prominent navigation link), and it would be automatically merged and deployed to production. We trust Dependabot to change our software’s behaviour because we have extensive tests of that behaviour, and we trust it to change our software’s visual appearance because we have visual regression tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how&quot;&gt;How&lt;/h2&gt;
&lt;p&gt;Setting up BackstopJS isn’t difficult. But I’m going to make it more difficult because we want to set it up in a way that’s repeatable (ie it always has the same result for the same version of the software) and automated. You don’t want your visual regression tests to be “flaky”, to pass some times and not others. It’s worth putting extra effort in to get this right, otherwise they may be less than useful. And you want them to be automated because that way you can trust yourself and others not to forget to run the test or update the snapshots, and you can use them as checks for Dependabot’s auto-merge.&lt;/p&gt;
&lt;p&gt;Ultimately, your workflow should look like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You push some horribly misguided code, introducing an unintended visual change.&lt;/li&gt;
&lt;li&gt;Your CI runs the visual regression tests and they fail, turning your build red.&lt;/li&gt;
&lt;li&gt;You look at BackstopJS’s test report from your CI, and spot the problem.&lt;/li&gt;
&lt;li&gt;You decide whether this change is acceptable, and either update the snapshots to this change or fix the code that caused this change.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;docker&quot;&gt;Docker&lt;/h3&gt;
&lt;p&gt;The first step to creating a repeatable visual regression test is to run the tests on the same platform every time. Otherwise, you’re in for trouble. Small changes in things like font rendering between operating systems can prevent the reference snapshots generated on your local machine from matching the test snapshots generated on your CI server. And if your CI server has multiple test runners on different platforms you’ve got even more unpredictability on your hands. To get around issues like these we use Docker containers via Docker Compose. This guarantees the same platform for every test run. This approach also has the advantage that you don’t need to install BackstopJS locally and end up with different versions of it on each developer’s machine; instead you have one consistent version, and Dependabot can keep it up-to-date. The disadvantage is of course that it’s slower.&lt;/p&gt;
&lt;p&gt;Add the following entry to your root &lt;code&gt;docker-compose.yml&lt;/code&gt; (&lt;a href=&quot;https://docs.docker.com/compose/gettingstarted/&quot;&gt;create one&lt;/a&gt; if necessary):&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  visual_regression_tests&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;backstopjs/backstopjs:4.4.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;./test/visual:/src&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This describes a &lt;code&gt;visual_regression_tests&lt;/code&gt; Docker container using the official &lt;code&gt;backstopjs&lt;/code&gt; image, version &lt;code&gt;4.4.2&lt;/code&gt;. The version can be left out, but it’s important that it be there for repeatability. You can use Dependabot to keep it up-to-date by creating a Dockerfile for it (until &lt;a href=&quot;https://github.com/dependabot/feedback/issues/82&quot;&gt;Dependabot adds Docker Compose support&lt;/a&gt;), which is &lt;a href=&quot;#customfonts&quot;&gt;described below&lt;/a&gt;. Of course, you should copy the latest version number from &lt;a href=&quot;https://hub.docker.com/r/backstopjs/backstopjs/builds&quot;&gt;the BackstopJS Docker image releases&lt;/a&gt; and use that; &lt;code&gt;4.4.2&lt;/code&gt; may be outdated at time of reading. If you’re using a Docker container for your website as well you should add &lt;a href=&quot;https://docs.docker.com/compose/compose-file/#depends_on&quot;&gt;a depends_on entry&lt;/a&gt; to that container.&lt;/p&gt;
&lt;p&gt;The last part is the key; the volume configuration &lt;code&gt;./test/visual:/src&lt;/code&gt;. This maps the local relative path &lt;code&gt;./test/visual&lt;/code&gt; to &lt;code&gt;/src&lt;/code&gt; in the container. You may change &lt;code&gt;./test/visual&lt;/code&gt; to any relative path you like, but &lt;code&gt;/src&lt;/code&gt; must be constant because that is where BackstopJS will look inside the container for it’s configuration.&lt;/p&gt;
&lt;h3 id=&quot;backstopjs&quot;&gt;BackstopJS&lt;/h3&gt;
&lt;p&gt;Previously, I said that with Docker developers don’t need to install a local instance of BackstopJS on their machines. This is true, but with one exception: You. That’s because for our next step we’re going to create the BackstopJS configuration, and you’ll need to use Backstop to create a default instance of the configuration. So try this:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;yarn&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; global&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; backstopjs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;mkdir&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; ./test/visual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; ./test/visual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;backstop&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; init&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First we install BackstopJS (NPM alternative: &lt;code&gt;npm install -g backstopjs&lt;/code&gt;) and then create the folder where our container expects to find the configuration (so change this as you like, but ensure it’s consistent with the Docker Compose volume). Then we open the folder and initialise a BackstopJS config there. This creates a few files; &lt;code&gt;backstop.json&lt;/code&gt;, and &lt;code&gt;backstop_data/engine_scripts&lt;/code&gt;. The engine scripts are basic defaults that determine how to run the browser emulator. Unless you’re doing something unusual you shouldn’t need to change most of them.&lt;/p&gt;
&lt;p&gt;Before going any further, create a &lt;code&gt;.gitignore&lt;/code&gt; in your BackstopJS folder with the following entries:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;backstop_data/bitmaps_test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;backstop_data/html_report&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will ensure that the test snapshots and HTML reports generated by Backstop are ignored by Git. You don’t want to commit these to version control, but you &lt;em&gt;do&lt;/em&gt; want to commit the other folder it generates; the snapshot references to test against.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;backstop.json&lt;/code&gt; file is your main means of interacting with BackstopJS and to start with should look something like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_default&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;viewports&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;phone&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;320&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;480&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFFFFF&quot;&gt;    …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;onBeforeScript&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;puppet/onBefore.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;onReadyScript&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;puppet/onReady.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;scenarios&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;BackstopJS Homepage&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;cookiePath&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/engine_scripts/cookies.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;url&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;https://garris.github.io/BackstopJS/&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;referenceUrl&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;readyEvent&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;readySelector&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;delay&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;hideSelectors&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;removeSelectors&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;hoverSelector&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;clickSelector&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;postInteractionWait&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;selectors&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;selectorExpansion&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;expect&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;misMatchThreshold&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; : &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;0.1&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;requireSameDimensions&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  &quot;paths&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    &quot;bitmaps_reference&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/bitmaps_reference&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    &quot;bitmaps_test&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/bitmaps_test&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    &quot;engine_scripts&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/engine_scripts&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    &quot;html_report&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/html_report&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    &quot;ci_report&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;backstop_data/ci_report&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFFFFF&quot;&gt;  …&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first thing I’d advise changing is the &lt;code&gt;viewports&lt;/code&gt; property. This property determines the resolutions that the site will be tested at. The default is not very extensive, and in my current team we’ve settled on the following viewport configuration:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#98C379&quot;&gt;  &quot;viewports&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;small&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;480&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;medium&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;814&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;768&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;large&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1066&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;814&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;xlarge&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1400&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1050&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;label&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;xxlarge&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;width&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1600&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;      &quot;height&quot;&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt;1200&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next interesting property is &lt;code&gt;scenarios&lt;/code&gt;. A scenario defines a test, and you’ll want to add one for each major section of your website. With a blog for example you may want to test the blog page and the blog list page, so you would have two scenarios.&lt;/p&gt;
&lt;p&gt;The real trick here that will lead you to either jubilation or despair is figuring out &lt;em&gt;when&lt;/em&gt; to take the snapshot. Browsers, Javascript, web services and HTTP are all such fickle beasts; they may load slightly faster or slower each time you create a snapshot. For your visual regression tests to be repeatable you need them to create the snapshot only when the page has finished loading. If you don’t you’ll find many test failures caused because the font hadn’t loaded in yet, or a pop-up hasn’t appeared yet, or a HTTP request to an AJAX dependency hadn’t completed yet, et cetra. As such &lt;em&gt;a lot&lt;/em&gt; of the scenario configuration options are about &lt;em&gt;when&lt;/em&gt; to decide that the page has finished loading. This is the real meat of the configuration and each possible option is documented in &lt;a href=&quot;https://github.com/garris/BackstopJS#using-backstopjs&quot;&gt;BackstopJS’s readme&lt;/a&gt;, but a few key ones to highlight are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cookiePath&lt;/code&gt;: This enables you to enter faked cookies into the browser emulator, this can be useful to send a token to an authenticated web service. Just set it to a relative path to a JSON file; the expected format is described in a sample file, &lt;code&gt;engine_scripts/cookies.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;: This is the full address of the web page being tested. If you’re using a Docker container to host your site you may use the name of the container, like &lt;code&gt;http://website:8080/myPage&lt;/code&gt;. Otherwise, you may run it locally and use something like &lt;code&gt;http://localhost:8080/myPage&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readyEvent&lt;/code&gt;: Listen out for a console log telling you the page is fully loaded before starting. This is useful for repeatability.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;readySelector&lt;/code&gt;: Similar to the above, this configures Backstop to wait until a particular element (defined by CSS selector) is appearing before starting. &lt;strong&gt;I recommend using this setting and setting it to something that won’t appear on any of your error pages&lt;/strong&gt;. If your service doesn’t work during a visual regression test you may not know until after you get the report and are staring at a diff between your reference and a 404 page. But if your &lt;code&gt;readySelector&lt;/code&gt; fails you get a timeout error in the output that lets you know that the expected page hasn’t loaded, so you get the feedback sooner.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delay&lt;/code&gt;: &lt;strong&gt;Avoid using this setting if you can&lt;/strong&gt;. It allows you to set an arbitrary time to wait for the page to load before assuming it’ll be ready to test. By default it is 0, which means no delay. If you find yourself using this setting, it’s because you haven’t found a reliable method to tell the browser that the page is loaded. You should only use this as an absolute last resort.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hideSelectors&lt;/code&gt;/&lt;code&gt;removeSelectors&lt;/code&gt;: If you have some problematic element on the page that you either can’t rely on to load in a reliable, timely fashion, or which has some random element that changes each time it’s loaded then you can hide those elements using either of these properties.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scrollToSelector&lt;/code&gt;: BackstopJS will capture the entire document, not just the visible section (unless configured otherwise). However, you may want to trigger some event via scrolling. This setting makes Backstop scroll to a particular selector.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;selectors&lt;/code&gt;: By default BackstopJS will capture the entire document. But if you want to test a specific set of regions, you can use this to limit the elements used to generate the snapshot. It’s the opposite of &lt;code&gt;hideSelectors&lt;/code&gt;/&lt;code&gt;removeSelectors&lt;/code&gt; (but they can be used together). It’s especially useful when you want to break a complex page down into smaller parts; you’ll get more specific feedback on individual components, making regressions easier to identify.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;misMatchThreshold&lt;/code&gt;: The degree to which two snapshots must be different before the scenario fails. This defaults to &lt;code&gt;0.1&lt;/code&gt; (That’s 0.1%, not 10%) and I wouldn’t increase it without good reason.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;running-the-tests&quot;&gt;Running the tests&lt;/h3&gt;
&lt;p&gt;At this point you should be able to run your tests. From the root of the project do &lt;code&gt;docker-compse run visual_regression_tests reference&lt;/code&gt;; this will generate your first reference images. Then try &lt;code&gt;docker-compose run visual_regression_tests test&lt;/code&gt;; this will generate new references and test them against the last ones you captured. I suggest recording these commands as scripts, so that every developer doesn’t have to remember them. In Yarn/NPM we add a script to &lt;code&gt;package.json&lt;/code&gt; for run these commands, otherwise we create a shell script inside a &lt;code&gt;./scripts&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Don’t worry if your tests aren’t passing the first time; I’ll explain some ways that you can improve their consistency and reliabiliy.&lt;/p&gt;
&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;Just in case I haven’t said this enough times: &lt;strong&gt;Repeatability is key&lt;/strong&gt;. One of the obstacles to this repeatability is ensuring that your dependencies are consistent. If you depend on a web service or a database that sends you some data to display on the page, then that service needs to send the same data every time the visual regression tests are run. This means that you need the capability to fake your dependencies. If you depend on a database, then you may want to achieve this by creating a Docker container of your particular database dependency with some minimal fake data. If you’re dependent on web services, then I’d recommend using &lt;a href=&quot;https://github.com/quii/mockingjay-server&quot;&gt;Mockingjay Server&lt;/a&gt;. It’s a Docker container around the mocking service Mockingjay. This makes for a painless and platform agnostic way to fake your dependencies with web services that respond with fake data. Just add something like the following to your &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  fake_my_service&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;quii/mockingjay-server:1.10.4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;./test/fakes:/fakes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    command&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;-config=/fakes/my_service.yaml -port=9099&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    ports&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;&quot;9099:9099&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For this to work you have to have a directory, here specified as &lt;code&gt;./test/fakes&lt;/code&gt;, with a YML file that specifies the endpoints to fake &lt;a href=&quot;https://github.com/quii/mockingjay-server#Running-a-fake-server&quot;&gt;following Mockingjay-Server’s format&lt;/a&gt;. This may include multiple fakes for different services. We specify which fake file to use in the &lt;code&gt;command&lt;/code&gt; property. Then, we just configure our web service to talk to this fake service when the tests are run. This way we know that our service will reliably, repeatably generate the same output and that’s a huge benefit to our testing.&lt;/p&gt;
&lt;h3 id=&quot;custom-fonts&quot;&gt;Custom Fonts&lt;/h3&gt;
&lt;p&gt;Downloading a non-default font from some server somewhere will take an unpredictable amount of time, so it harms our repeatability. Rather than reaching for that unreliable &lt;code&gt;delay&lt;/code&gt; setting, however, we can pre-install the fonts on the Docker image to get around this problem altogether. Simply create a &lt;code&gt;Dockerfile&lt;/code&gt; inside your BackstopJS directory with an entry like the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FROM backstopjs/backstopjs:4.4.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y fonts-lato&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y fonts-font-awesome&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a very basic Dockerfile that extends the official BackstopJS image (remember to include the version!) and uses &lt;code&gt;apt-get&lt;/code&gt; to install the requisite fonts. This way the browser emulator won’t need to download the fonts as they’re already installed. You should be able to find the package name of any font you need by searching &lt;a href=&quot;https://www.debian.org/distrib/packages&quot;&gt;Debian’s package registry&lt;/a&gt;. Then you just need to change your docker-compose entry to build your BackstopJS directory, like so:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;  visual_regression_tests&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;./tests/visual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E06C75&quot;&gt;    volumes&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt;./test/visual:/src&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;continuous-integration&quot;&gt;Continuous Integration&lt;/h3&gt;
&lt;p&gt;You’ll want to add a step to your build to run the visual regression tests. If you created a script to run the tests earlier then you can simply plug it in here. Because we’re using Docker you needn’t install BackstopJS on your CI server, and it will play nicely with Docker-based CI systems like CircleCI. There is an important extra step though; you need to extract the build artifact from  BackstopJS. Otherwise, you won’t be able to see why your tests have failed.&lt;/p&gt;
&lt;p&gt;For Jenkins you can achieve this with the &lt;a href=&quot;https://wiki.jenkins.io/display/JENKINS/HTML+Publisher+Plugin&quot;&gt;HTML Publisher Plugin&lt;/a&gt;. Though the &lt;a href=&quot;https://github.com/garris/BackstopJS/tree/master/examples/Jenkins&quot;&gt;official jenkins support guide&lt;/a&gt; involves setting up a Jenkins job in the traditional web interface, I’d advise against that and use &lt;a href=&quot;https://jenkins.io/blog/2017/02/10/declarative-html-publisher/&quot;&gt;the declarative Jenkinsfile method&lt;/a&gt;. If you already have a declarative Jenkinsfile just add something like the following to your &lt;code&gt;always&lt;/code&gt; post-step in your Jenkinsfile:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;post {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  always {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    publishHTML(target: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      allowMissing: false,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      alwaysLinkToLastBuild: true,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      keepAll: true,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      reportDir: &apos;./test/visual/backstop_data&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      reportFiles: &apos;html_report/index.html&apos;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      reportName: &apos;Visual Regression Tests Report&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;testing-repeatability&quot;&gt;Testing Repeatability&lt;/h2&gt;
&lt;p&gt;Lastly, to ensure repeatability you can actually &lt;em&gt;repeat&lt;/em&gt; the tests. When first setting up any tests involving browser emulation or browser automation I won’t accept a passing test as correct unless it passes many times, so I can be confident that it isn’t going to prove unreliable (“flaky”) in the future. A simple Bash script like the following will suffice:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf;overflow-x:auto&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#56B6C2&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#D19A66&quot;&gt; -e&lt;/span&gt;&lt;span style=&quot;color:#7F848E;font-style:italic&quot;&gt; #ensures the script will halt if any of the test runs fail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;0..19}&lt;/span&gt;&lt;span style=&quot;color:#ABB2BF&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#61AFEF&quot;&gt;  yarn&lt;/span&gt;&lt;span style=&quot;color:#98C379&quot;&gt; test:visual&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#C678DD&quot;&gt;done&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, it may take a while to run. Just leave it running in the background while you’re doing something else.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There are a number of other approaches to running BackstopJS, but this is the best type of setup I’ve found. Hopefully I’ve equipped you with everything you’ll need to get up and running with repeatable BackstopJS visual regression tests on your websites. &lt;a href=&quot;https://twitter.com/mattsijansky&quot;&gt;Let me know&lt;/a&gt; how you get on.&lt;/p&gt;</content:encoded></item><item><title>Open Rights Group Conference 2019 Review</title><link>https://www.matt.si/2019-10/orgcon/</link><guid isPermaLink="true">https://www.matt.si/2019-10/orgcon/</guid><description>A review of ORG&apos;s 2019 digital rights conference</description><pubDate>Sat, 02 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In July I attended this year’s Open Rights Group Conference, a one-day multi-track conference organised by the Open Rights Group (ORG). ORG is the UK’s biggest advocacy group for digital rights and campaigns on issues like surveillance, net neutrality and censorship. Despite being a member for many years this is only the second time I’ve attended an ORGCon, and it was honestly one of the best tech-related events I’ve been to all year. It’s not exclusively for techies, on the contrary I was in the minority. There were many more journalists, activists and lawyers there. I’ll dive into what made it great, describing each fascinating session I attended.&lt;/p&gt;
&lt;h2 id=&quot;session-one--keynote-by-edward-snowden&quot;&gt;Session one- Keynote by Edward Snowden&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-snowden.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-snowden.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Image from &lt;a href=&quot;https://twitter.com/greekemmy/status/1149971927848669184&quot;&gt;@greekemmy&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt; 
&lt;p&gt;For the first session of the day American whistleblower Edward Snowden gave a keynote speech followed by Q&amp;amp;A, via videocall from Russia. No-one in the room missed the irony of relying on Google’s Hangouts service to talk at a digital rights conference, and the audio was appropriately unreliable. In spite of that Snowden delivered an enlightening, inspiring speech. On discussing his whistleblowing, he made an interesting clarification: That his motivation was about democracy, not about surveillance. What disturbed him more was not the orwellian surveillance of hundreds of millions of innocent people, but the fact that none of them had agreed to it. The fact that there’d been no debate, no chance to object before this policy was implemented. Other highlights from the session:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He very heavily criticised the Ghost Proposal, a GCHQ bid to encrypt all our communications with a key that only the government can decrypt&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. Specifically he referred to how the NSA lost track of some of their most valuable digital assets that were then used by malicious actors cause huge amounts of damage&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, and questioned whether the “rinky-dink UK government” (with tongue firmly in cheek, I’m sure) would be able to protect a set of keys that anyone could use to decrypt millions of people’s communications.&lt;/li&gt;
&lt;li&gt;“The law does not protect society, society protects the law”; Snowden made the argument that laws are tools and only effective so long as conscientious citizens use them and uphold them.
&lt;ul&gt;
&lt;li&gt;He further arguded that technology is another tool that, like law, can and should be utilised to enforce human rights. One obvious example is encryption; it should surely be illegal to eavesdrop your communications without due process, but encrypting one’s communications is another way to enforce that principle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;He ended his speech on an inspiring note; “We will lose this year and the next one, but we will win- it’s a way of life, a system of beliefs that will not go away, what we did to resist governmental abuse of surveillance will matter to our children” (paraphrased to the best of my memory).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;session-two--how-can-i-trust-what-i-see-online-panel-from-teen-ai&quot;&gt;Session two- “How Can I Trust What I See Online?” panel from Teen AI&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-teenai.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-teenai.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Image from &lt;a href=&quot;https://medium.com/@AcornAspiration/truth-fiction-and-accountability-how-can-i-trust-what-i-see-online-orgcon-panel-2019-18a443b1b41c&quot;&gt;Acorn Aspirations&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt; 
&lt;p&gt;This panel consisted of four teenagers from Teen AI who’ve been studying computers, security and AI as well as attending various tech events for young people. It was really inspiring to see young people so interested in technology, they were each well in advance of where I’d been at their age. Unfortunately I’ve forgotten exactly which panelists said what, having misplaced some notes. Nontheless, my highlights were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One panelist made the point that deepfakes may actually make us trust what we see less, thereby making us more skeptical. This may be a positive change in society rather than the bleak forecasts that we usually associate with deepfake tech.&lt;/li&gt;
&lt;li&gt;One panelist when aksed whether young people need to be taught how to be safe online responded “No, old people do”. They went on to discuss how young people are that much more tech-savvy and more likely to understand what they’re looking at, while it may be that older people are more susceptible to misleading or malicious content.&lt;/li&gt;
&lt;li&gt;“If we don’t understand technology we will be controlled by people who do”- a wonderful response from one of the panelists discussing their motivations for learning about technology.&lt;/li&gt;
&lt;li&gt;Another panelist said something that was very novel to me, when making the point that technology is not inherently good or bad. I’ve always thought of facial recognition as being an inherently orwellian and oppressive tool, but they cited a much more positive example: Police in New Delhi are using it to locate missing children&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. This is one of those wonderfully simple yet effective ideas; go around taking pictures of children at orphenages, use facial recognition to compare them to the faces of missing children that their family have posted online. In just the first four days they identified 3,000 missing children.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;session-three--can-tech-be-truly-ethical&quot;&gt;Session three- Can Tech be Truly Ethical?&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-ethics-panel.jpg&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-ethics-panel.jpg&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;figcaption&gt;Image from &lt;a href=&quot;https://twitter.com/DavidRaho/status/1149998408075272193&quot;&gt;David Raho&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This was a fantastic session, it really began to open my eyes to how complex ethics in technology can get. We had Paul Dourish (University of California), Lilian Edwards (Newcastle University), Ann Light (University of Sussex) and Gina Neff (University of Oxford) discussing the topic, and each demonstrated obvious expertise in the subject. Among numerous enlightening moments were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“Ethics washing”- a new term to me; it refers to the tendency of organisations to create an ethics board, often entirely internally with no public oversight or transparency, and declare themselves to now be ethical. The accusation is that such organisations are trying to escape true scrutiny and regulation by saying “We’re ethical now, so there’s no need to regulate us”.&lt;/li&gt;
&lt;li&gt;Ethical behaviour can be difficult to enforce because of combinatorial complexity. This is an especially significant issue with Internet of Things devices, filling homes and interacting with one another. You may ensure your software acts ethically in as many ways as you can think of, but your software will very frequently find itself in situations that you hadn’t imagined. When a thousand different devices are capable of interacting with one another, we can’t predict every interaction ahead of time.
&lt;ul&gt;
&lt;li&gt;This may be a good use case apply property-based testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;One person in the audience was a member of a worker-owned software business, which is the first time I’ve heard of such a thing. It sounds like a great development.&lt;/li&gt;
&lt;li&gt;“How do we stop a raging bull”- while we’re clamouring to figure out what technology’s role in society is and how it affects all of us, technology continues to develop rapidly and crosses new boundaries into new parts of our lives every day. It’s a lot easier to start a fire than to put it out; how can ethicists and human rights campaigners keep from always being caught on the back foot?
&lt;ul&gt;
&lt;li&gt;It was suggested that we should look at business models, and the way different revenue sources can affect a business’ motivations. Right now, huge swathes of the tech industry are profiting from automated surveillance of their users. What revenue sources could offer more ethical motivations?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;It’s one rule for them, one rule for us: San Francisco has banned facial recognition within the city&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;. Yet many of the city’s occupants are affluent technologists making their money by continually improving the very same problematic technologies that they’re exempt from, and much of the rest of the world is increasingly subjected to.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.jstor.org/stable/20024652&quot;&gt;Do Artifacts Have Politics&lt;/a&gt; was dropped in as a piece of recommended reading.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;session-four--facial-recognition-is-now-a-reality-in-the-uk&quot;&gt;Session four- Facial Recognition is Now a Reality in the UK&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-facial-recognition.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-facial-recognition.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This panel was packed with talented and interesting people- a senior technology correspondent at The Financial Times, the director of Big Brother Watch, the Chair of the London Policing Ethics Panel, and Sian Berry co-leader of the Green Party. The topic was on facial recognition in the UK, and in particular how it’s been deployed at Notting Hill Carnival in recent years. The Met Police started using the technology without notice or discussion, and studies have found that it’s grossly ineffective&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;. My notes from the session:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Met Police didn’t admint to using the technology until Big Brother Watch pushed the issue.&lt;/li&gt;
&lt;li&gt;There is no basis in law for the use of facial recognition. No-one knows whether it is something that needs to be consented to under UK law, or what limitations there are on it.&lt;/li&gt;
&lt;li&gt;There is an ongoing legal battle, brought by Big Brother Watch, to decide the legitimacy of facial recognition in UK law&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Suzanne Shale was a great balancing voice representing the Policing Ethics Panel, and the discussion was much less partisan or one-sided for having her there.&lt;/li&gt;
&lt;li&gt;Sian Berry assured the audience that progress was being made, and the Met Police would be putting a memorandum on place on the use of facial recognition technology.&lt;/li&gt;
&lt;li&gt;Another issue was raised regarding regulation of private facial recognition, taking the cameras in self checkout machines as a particular example. They’re constantly facing outward from behind the screen and have a clear view of the consumer. They could be, and may currently be, used to build facial recognition databases and map them to our cards and purchasing histories. There’s currently little if any regulation to prevent this.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;session-five--the-encryption-dilemma&quot;&gt;Session five- The Encryption Dilemma&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-ghost-proposal.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-ghost-proposal.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This was perhaps my favourite session, it was really remarkable and speaks to the integrity of the organisers and the whole community. The first thing to notice in the picture is that Dr. Ian Levy is missing a photograph. This is because he was added at the last possible minute. This session was supposed to be a one-on-one interview, where Cori Crider and the audience asks questions of Nate Cardozo, privacy policy manager at Facebook and former senior policy-maker at the Electronic Frontier Foundation (EFF), the biggest digital rights advocacy group in the United States.&lt;/p&gt;
&lt;p&gt;Today Nate mostly works with WhatsApp, which is setting new standards for private digital communications by popularising the end-to-end encryption model. This model is infuriating to the likes of GCHQ because it removes their ability to intercept communications. GCHQ’s Ghost Proposal is supposed to be a middle-ground where end-to-end encryption can exist between a server and their client, but the state can sit in the middle and read everything. Nate is a big time digital privacy advocate and a very outspoken critic of the Ghost Proposal. He even wrote a well publicised article for the EFF in which he called the Ghost Proposal a “backdoor by another name”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7&quot; id=&quot;user-content-fnref-7&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Enter Dr. Ian Levy, co-author of The Ghost Proposal and Technical Director of the Cyber Security Centre (a part of GCHQ). I gather that he found out about this interview and argued that that, as it was obviously going to center around the ghost proposal, he ought to have an opportunity to defend the proposal. So at the twilight hour the planned session turns from an interview into a debate, and Ian is added to the session. I think it’s really wonderful that we can have a nonpartisan debate like this. I really admire Ian for coming to the event knowing that the audience would largely disagree with him and to ORG, Cori and Nate for doing the right thing by giving Ian this chance, and avoiding the conference becoming an echo chamber. Here are my highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ian went to great lengths to make the point that he wishes to genuinely engage with the digital rights community, to come to a common understanding and find some resolution for the encryption debate that satisfies everyone. Needless to say this is something that GCHQ and the like have an extremely poor track record of, so it’s great to see someone making a change. “The fact I’m here should tell you something”, Ian says, and it does.&lt;/li&gt;
&lt;li&gt;Ian insists that the Ghost Proposal is nothing more than a proposal and says that he wants to use it to trigger debate, to iterate on this idea and get public discussions moving.&lt;/li&gt;
&lt;li&gt;The end-to-end encryption model is coming to Facebook Messenger too.&lt;/li&gt;
&lt;li&gt;Questioned on WhatsApp security, Nate assures the audience and adds: “If I leave in a huff, stop using WhatsApp”.&lt;/li&gt;
&lt;li&gt;Ian responded really well to a difficult question- “If we introduce a backdoor, won’t terrorists just write their own encryption?”. Ian responds that he’d love that. Cryptography, he argues, is &lt;em&gt;hard&lt;/em&gt;. Unless you’re an expert cryptographer, when writing your own encrypted communication software you’re almost certain to make a mistake that intelligence services can exploit.&lt;/li&gt;
&lt;li&gt;Ian, perhaps as part of trying to humanise his work and reach out to people, recommends the “Top Secret” exhibition at the Science Museum as a great way to learn the history of GCHQ.&lt;/li&gt;
&lt;li&gt;There was a great question from the crowd criticising the Ghost Protocol- “Are you leading the way by using it in all internal GCHQ messaging? Do the royals use it?”. Going back to the point of “one rule for us, another for them”; GCHQ would obviously resist any attempt to weaken their own communication privacy, as would the more affluent members of society.&lt;/li&gt;
&lt;li&gt;The discussion also went briefly into Cloudflre’s DNS over HTTPs. Ian and GCHQ are very much not fond of this as it once again makes tracking people on the internet more difficult. Conversely, I must say I’m quite enamored with the idea.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;session-six--jack-poulson-on-censorship&quot;&gt;Session six- Jack Poulson on Censorship&lt;/h2&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-censorship.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-censorship.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Jack Poulson is known for quite publicly leaving Google, where he was a Senior Research Scientist, over their “Dragonfly” project to censor search results in China&lt;sup&gt;&lt;a href=&quot;#user-content-fn-8&quot; id=&quot;user-content-fnref-8&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;. The project would have blocked results for searches like “human rights”, “Nobel Prize” and “student protest”&lt;sup&gt;&lt;a href=&quot;#user-content-fn-9&quot; id=&quot;user-content-fnref-9&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;. My notes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Challenged on what he had expected his resignation to do, Jack pointed out the successes Google staff have had in changing their employer’s policy&lt;sup&gt;&lt;a href=&quot;#user-content-fn-10&quot; id=&quot;user-content-fnref-10&quot;&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Jack made a similar stance when he worked in academia, refusing to support closed access journals. He was threatened with tenure removal if he didn’t comply, and resigned two days later.&lt;/li&gt;
&lt;li&gt;Google first shut down Google.cn because China attacked them, compromised their source code and more in order to track human rights activists&lt;sup&gt;&lt;a href=&quot;#user-content-fn-11&quot; id=&quot;user-content-fnref-11&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;li&gt;Jack suggests that we too often discuss ethics in a future tense, as if it were theoretical- “Oh, what if technology were to harm society…” but tech already is harming society. It’s better, he argues, to refer to actual historical human rights abuses, such as when Cisco wrote software for the Chinese government knowing that it would be used to detain and torture dissidents&lt;sup&gt;&lt;a href=&quot;#user-content-fn-12&quot; id=&quot;user-content-fnref-12&quot;&gt;12&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;art-installations&quot;&gt;Art installations&lt;/h2&gt;
&lt;p&gt;Lastly, there were a number of interesting art installations around the conference. I particularly liked these:&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-zuck.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-zuck.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This display demonstrated the amount of land that Mark Zuckerberg has purchased, at great expense, around his home to ensure privacy. The author asks; are we entering a world where only the rich can afford privacy?&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-alphabet.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-alphabet.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;A children’s connect-the-dot game in which each dot is a subsidiary of Alphabet, Google’s parent company. A great way to visually demonstrate the sheer scale technology corporations are reaching.&lt;/p&gt;
&lt;div id=&quot;content-figure&quot; style=&quot;width:100%;margin:0 auto&quot;&gt;&lt;figure&gt;&lt;div class=&quot;img-placeholder&quot;&gt;&lt;a href=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-informatics.png&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://www.matt.si/_figure-images/2019-10/orgcon/orgcon19-informatics.png&quot; alt=&quot;&quot; style=&quot;width:100%&quot; loading=&quot;lazy&quot; class=&quot;figure-img&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Each talk in the biggest room was accompanied by an artist drawing a wonderful piece to summarise the topics covered in the talk.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;ORGCon is great. I never imagined I’d learn so much about ethics in technology. There were some really unexpected and interesting sessions. I definitely recommend going next year, and perhaps you’ll consider &lt;a href=&quot;https://www.openrightsgroup.org/join/&quot;&gt;joining the Open Rights Group&lt;/a&gt;.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Alex Hearn, The Guardian, &lt;a href=&quot;https://www.theguardian.com/uk-news/2019/may/30/apple-and-whatsapp-condemn-gchq-plans-to-eavesdrop-on-encrypted-chats&quot;&gt;Apple and WhatsApp Condem GCHQ Plans to Eavesdrop on Encrypted Chats&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Nicole Perlroth, David E. Sanger, New York Times, &lt;a href=&quot;https://www.nytimes.com/2019/05/06/us/politics/china-hacking-cyber.html&quot;&gt;How Chinese Spies Got the N.S.A.’s Hacking Tools, and Used Them for Attacks&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Anthony Cuthberston, The Independent, &lt;a href=&quot;https://www.independent.co.uk/life-style/gadgets-and-tech/news/india-police-missing-children-facial-recognition-tech-trace-find-reunite-a8320406.html&quot;&gt;Indian Police Trace 3,000 Missing Children In Just Four Days Using Facial Recognition Technology&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;Dave Lee, BBC News, &lt;a href=&quot;https://www.bbc.co.uk/news/technology-48276660&quot;&gt;San Francisco is first US city to ban facial recognition&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;Matt Burgess, Wired.co.uk, &lt;a href=&quot;https://www.wired.co.uk/article/met-police-london-facial-recognition-test&quot;&gt;The Met Police’s facial recognition tests are fatally flawed&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;Big Brother Watch, &lt;a href=&quot;https://bigbrotherwatch.org.uk/all-media/big-brother-watch-begins-landmark-legal-challenge-to-police-use-of-facial-recognition-surveillance/&quot;&gt;Big Brother Watch Begins Landmark Legal Challenge to Police Use of Facial Recognition Surveillance&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7&quot;&gt;
&lt;p&gt;Nate Cardozo, EFF, &lt;a href=&quot;https://www.eff.org/deeplinks/2019/01/give-ghost-backdoor-another-name&quot;&gt;Give Up the Ghost: A Backdoor by Another Name&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-7&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-8&quot;&gt;
&lt;p&gt;Ryan Gallagher, The Intercept, &lt;a href=&quot;https://theintercept.com/2018/09/13/google-china-search-engine-employee-resigns/&quot;&gt;SENIOR GOOGLE SCIENTIST RESIGNS OVER “FORFEITURE OF OUR VALUES” IN CHINA&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-8&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-9&quot;&gt;
&lt;p&gt;Anthony Cuthberston, The Independent, &lt;a href=&quot;https://www.independent.co.uk/life-style/gadgets-and-tech/news/google-china-project-dragonfly-cancelled-protest-censored-a8808541.html&quot;&gt;GOOGLE EMPLOYEES SUSPECT IT IS STILL WORKING ON SECRET CHINESE ‘DRAGONFLY’ PROJECT&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-9&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-10&quot;&gt;
&lt;p&gt;Daisuke Wakabayashi, Scott Shane, New York Times, &lt;a href=&quot;https://www.nytimes.com/2018/06/01/technology/google-pentagon-project-maven.html&quot;&gt;Google Will Not Renew Pentagon Contract That Upset Employees&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-10&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-11&quot;&gt;
&lt;p&gt;Elinor Mills, CNet, &lt;a href=&quot;https://www.cnet.com/news/behind-the-china-attacks-on-google-faq/&quot;&gt;Behin the China attacks on Google&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-11&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-12&quot;&gt;
&lt;p&gt;Stephen Lawson, CIO, &lt;a href=&quot;https://www.cio.com/article/3021959/eff-says-cisco-shouldnt-get-off-the-hook-for-torture-in-china.html&quot;&gt;EFF says Cisco shouldn’t get off the hook for torture in China&lt;/a&gt; &lt;a href=&quot;#user-content-fnref-12&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item></channel></rss>