<?xml version="1.0" encoding="utf-16"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <atom:link rel="self" type="application/rss+xml" href="https://mythicant.com/" />
    <title>Mythicant Games</title>
    <link>https://mythicant.com/</link>
    <description />
    <copyright>© 2026</copyright>
    <language>en</language>
    <item>
      <title>On Pair Programming</title>
      <link>https://mythicant.com/blog/on-pair-programming</link>
      <description />
      <pubDate>Tue, 30 Apr 2024 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>In an online community I'm a part of, recently someone was asking some questions about pair programming. Specifically they were asking about how to get started with pair programming, how to influence their team/org to adopt it, as well as generally why they might want to do pair programming. I thought I'd take a crack at answering those questions and share my thoughts on the topic.</p>

<p>As a little context, I've done primarily pair or mob programming for the last 12-ish years of my software development career. For the 10-ish years before that, I was working primarily solo coding, with some occasional collaborative work, but nothing I would consider dedicated pair programming.</p>

<h3>Getting Started</h3>

<p>I want to start with the question "How Do I Get Started with Pair Programming?" </p>

<ul>
<li>Ideally, find someone else who is also interested in pair programming. If you're trying to learn how to pair program <em>and</em> trying to convince someone to pair program at the same time, your job will be harder.</li>
<li>Start small. If pairing on actual code is too much, try pairing on a <a href="http://codekata.com/">code kata</a>.</li>
<li>Start short. Pair programming is a skill you need to develop over time. Going from zero pairing to pairing for eight hours straight will be a big jump. It's okay if you only pair for 30 or 60 minutes before you and your pair are ready for a break. If you both are up for more, great, but don't push so hard that you get burned out.</li>
<li>Make sure you can both contribute. If your first pairing session is one person typing and one person watching, that may not be a great experience. Both members of the pair should be able to see all the code and contribute to that (whether in person or remote).</li>
<li>Don't worry about doing it "the wrong way." There are lots of different ways to do pair programming. Find what works for you. <a href="https://martinfowler.com/articles/on-pair-programming.html">This article</a> on Martin Fowler's site has a lot of ideas. If you're not sure, I'd suggest you start with Ping Pong pairing and <a href="http://llewellynfalco.blogspot.com/2014/06/llewellyns-strong-style-pairing.html">Strong-style pairing</a> and iterate from there.</li>
</ul>

<h3>How Do I Influence My Team/Org?</h3>

<p>This one can be hard. Influencing people (even ourselves) to change their behavior is hard even at the best of times. For general guidance on influencing change, I'd highly recommend the books <a href="https://fearlesschangepatterns.com/">Fearless Change and More Fearless Change</a>. Both are excellent.</p>

<p>A lot of the items from the Getting Started section above are your best bet. Achieving small successes and progressing from there is almost always more likely to succeed than any kind of big bang approach.</p>

<p>It may be worth doing some initial investigation to see if there are areas of the management hierarchy that are vehemently opposed to pair programming. Supportive leadership can be a great asset in adopting pair programming, but leadership that is against it can kill it just as quickly.</p>

<h3>Why Would I Want To Pair Program?</h3>

<p>And finally, why would you want to pair program at all? Isn't it a waste of time? Couldn't two people working separately work twice as fast as two working together? Isn't it uncomfortable always having someone looking over your shoulder?</p>

<p>There definitely can be some downsides to pair programming, especially when implemented poorly or when working with an incompatible partner. But for me, I've found the pros to outweigh the cons. Here are some of those pros as I see them:</p>

<ul>
<li>You're always getting the best out of two ideas, rather than just the best you can come up with at the time. Is it possible for two people working together to come up with two ideas that both suck? Sure, but it's a lot less likely than with just one person.</li>
<li>Real time code reviews. Rather than waiting for asynchronous code reviews (like in a traditional PR model) you get a code review the instant you need it. You also get it <em>before</em> you write a bunch of code that relies on incorrect assumptions. In other words, you get feedback faster.</li>
<li>It helps me stay focused better. It's easy for me to get caught up in making relatively minor decisions that don't matter than much. It's often easier for the other person and me to come to a decision much more quickly than when I'm working by myself.</li>
<li>The learning can be amazing. The other person you're working with is presumably an expert on one or more things you're not. That might be the programming language you're using, the tools you're working with, or the problem domain. If they are, you can soak up tons of their knowledge in a relatively short period of time. And if they aren't an expert, that means <em>you</em> are (even if only when compared to them) and they can suck up your knowledge.</li>
<li>It's easier to have a sense of shared code ownership. I'm of the opinion that for virtually all production code, it's superior to have that code owned by a group of people rather than a single individual. When you work on code with another person it's a lot easier to think of the code as "our code" than it is when you write it in isolation.</li>
</ul>

<h3>Conclusion</h3>

<p>Pair programming can be hard, especially if you're just starting out with it. It can be uncomfortable. At least one other person will see the messy, sometimes wandering way you get the results that you do. You'll probably have to say, "I don't know" more than you do when you code on your own. And you'll be amazed and embarrassed at how you lose all ability to type when another person is watching.</p>

<p>But for me at least, working through that discomfort has made me a better developer. That's not just because of the benefits I've experienced with pair programming. But also because going through that discomfort makes me humbler and more empathetic as a human being.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Junior Developer Cheat Sheet</title>
      <link>https://mythicant.com/blog/junior-developer-cheat-sheet</link>
      <description />
      <pubDate>Wed, 27 Dec 2023 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>A friend of mine asked me the other day about learning resources for some junior developers he knows. I sent him a list of a few resources off the top of my head. But my brain kept thinking of others to suggest. So I figured I'd write down a list with a bit more thought put in to it.</p>

<h1>Disclaimer</h1>

<p>By putting together this list, I'm not implying that every junior developer should immediately use every single one of these resources. Even after 20 years of professional software development there are still books that I should have read but haven't, or coding problems I should have implemented but haven't. Please don't look at this list as a wall of "look at all the things I haven't done" shame. I hope people will look at it more as a list of things they could learn more about.</p>

<p>And hopefully it's obvious, but this is by no means a complete list. I'm sure there will be resources that I would have put on here given only a little more thought on my part, not to mention all the resources from other peoples' experiences and opinions. But this is my list, so I'm not going to worry about every else's lists right now.</p>

<h1>Books</h1>

<p>There are a lot of good books related to software development these days. One could argue that there are too many good books and no one has time to read them all. That's probably true. But here are a few that I often recommend to people:</p>

<ul>
<li><p>For some basic, all around good software development advice, <code>The Pragmatic Programmer</code> by Dave Thomas and Andy Hunt is a great read for any software developer.</p></li>
<li><p>I'm a big fan of the ideas from the software craftsmanship movement. Some books that I think have a lot of valuable material on the topic include <code>The Software Craftsman</code> by Sandro Mancuso and <code>The Clean Coder</code> and <code>Clean Craftsmanship</code> by Robert Martin.</p></li>
<li><p><code>Test Driven Development By Example</code> by Kent Beck is kind of like sitting next to Kent Beck as he writes code using TDD, just in book format. It's great to be able to learn directly from one of the masters of TDD. If you're just looking to learn more about unit testing in general, this book might be a bit more than you want.</p></li>
<li><p>I wish I'd had the book <code>Apprenticeship Patterns</code> by Dave Hoover and Adewale Oshineye when I was starting out my career. It has a bunch of patterns (surprising given the name, I know) about how to learn and grow in your career as a software developer.</p></li>
<li><p>Ron Jeffries' <code>The Nature of Software Development</code> is a good discussion of the principles of agile software development, without all the baggage that Scrum and its following bring. I think he intended it more for engineering managers, but I think it's approachable enough that pretty much any software developer could benefit from it.</p></li>
<li><p>In addition to agile software development, I think knowing about lean software development would benefit most software developers. <code>This is Lean</code> by Niklas Modig and Par Ahlstrom is a great intro to lean principles in general. If you want to go super in-depth, <code>Principles of Product Development Flow</code> by Don Reinertsen is great. But beware! It is pretty deep. If you want something more specific to software development, <code>Implementing Lean Software Development</code> by Mary and Tom Poppendieck is pretty awesome.</p></li>
<li><p>If you have code that doesn't have tests and you want to learn how to get it under test, <code>Working Effectively With Legacy Code</code> by Michael Feathers is <em>the</em> book on the topic.</p></li>
</ul>

<p>Like I said, it could be argued that there are too many good books on software development. And I could certainly add many more books to the "good" list. But I think this is a good list of topics that junior devs might otherwise not get exposed to.</p>

<h1>Katas</h1>

<p>There are some ideas and concepts that can be communicated well in books. But there are other ideas that translate better when learned through actually coding. </p>

<p>The idea of a kata comes from martial arts, where the same forms are practiced repeatedly. Code katas are slightly different, but with a similar intent. They are specific problems that can be repeated to practice various software development skills such as refactoring, test driven development, pair programming, etc.</p>

<p>Some of these code katas are fairly simple, self-contained problems. Some examples include</p>

<ul>
<li>The <a href="https://github.com/UtahSC/roman-numeral-kata">Roman Numeral Kata</a> is one of my favorites for practicing test driven development.</li>
<li><a href="https://flexboxfroggy.com/">Flexbox Froggy</a> is a great way to practice using flexbox in CSS.</li>
<li>The <a href="https://github.com/emilybache/GildedRose-Refactoring-Kata">Gilded Rose Kata</a> is a great kata that focuses on refactoring and getting mostly untested code under test.</li>
<li>There are lots of other lists of general code katas. The <a href="http://utahsc.org">Utah Software Craftsmanship</a> group has a <a href="https://github.com/UtahSC/coding-exercises?tab=readme-ov-file#examples-exercises">list of common code katas</a> (which includes the Roman Numeral Kata). There is also <a href="https://github.com/gamontal/awesome-katas">this list</a> as well as many others.</li>
<li>Emily Bache (the author of the Guilded Rose Kata mentioned above) has a <a href="https://github.com/emilybache?tab=repositories">large list of katas</a> she has created, many of which are focused on refactoring.</li>
</ul>

<p>Small, self-contained problems are great for some types of practice. But sometimes it's helpful to have a real world (or at least closer to real world) problem to practice with and learn from. Personal side projects can be a great way to do this. But sometimes it's hard to come up with good inspiration for a side project you're passionate about. In that case, a closer-to-real-world code kata might help. Here are a few examples:</p>

<ul>
<li><a href="https://xortag.azurewebsites.net/">XorTag</a> - Write code to play tag with other players in real time over HTTP. This kata involves making HTTP calls and sending and parsing JSON. It's best done with a group, but can be done solo as well.</li>
<li><a href="https://github.com/davidadsit/distributed-calculator">Distributed Calculator</a> - Another kata that uses interactions over HTTP. But this one has you creating your own web server that interacts with another web application.</li>
<li><a href="https://github.com/theparticleman/VanillaWebKata">Vanilla Web</a> - With web applications it can be easy to get caught up in all the latest front-end frameworks. Sometimes it's nice to remember that all you really need to create a website is some HTML, CSS, and Javascript text files created using a simple text editor. This kata is about practicing those skills.</li>
</ul>

<p>A few more honorable mentions:</p>

<ul>
<li><a href="https://adventofcode.com/">Advent of Code</a> - Advent of Code is a coding-based advent calendar that gets updated every December. The problems are usually fairly algorithm focused, but they can be great if that's the type of thing you're practicing. You can always go back and solve the problems from previous years too.</li>
<li><a href="https://exercism.org/">Exercism</a> - Exercism used to be all about solving toy problems and getting feedback from others on your solution. But now it has all kinds of learning paths and other things as well. Check it out and see if it would help meet some of your learning needs.</li>
</ul>

<h1>Other Stuff</h1>

<p>Sometimes reading a book is the right way to learn. Other times writing some code is the right way to learn. And still other times something completely different is in order. Here are a few resources in the "completely different" category:</p>

<ul>
<li><a href="https://www.coderetreat.org/">Code Retreat</a> - The idea of a code retreat is all around practice and does typically involve coding. But it's more about challenging your preconceptions about how code can and should be written than it is about the specific code you write. Rather than explain all the details about how a code retreat works, I'll just let you read on the website. But if you get the chance to participate in a code retreat, I would highly recommend it. There is a Global Day of Code Retreat event every year, usually in November.</li>
<li><a href="https://www.youtube.com/@codingwithjonandmike3931">Coding with Jon and Mike</a> - When learning some types of skills, it can be helpful to see someone else actually using those skills. My friend Mike and I have put together some YouTube videos to show people actually practices skills like pair programming, test driven development, and refactoring.</li>
<li><a href="https://www.youtube.com/@EmilyBache-tech-coach">Emily Bache videos</a> - Emily Bache (already mentioned above) has recently started her own YouTube channel with videos on topics like refactoring and test driven development. I've only watched a few of her videos so far, but look forward to getting to help people practice using them more in the future.</li>
</ul>

<h1>Conclusion</h1>

<p>Again, this is by no means an exhaustive list. If you have other must-have learning resources that you think should be on this list, <a href="/contact">let me know</a>. And if you haven't (or don't ever) get to everything on this list, don't feel bad! But if you're looking for ways to practice and learn new skills so you can level up from a junior developer and progress in your career, hopefully some of the things in this list help!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Can ChatGPT Do Test-Driven Development?</title>
      <link>https://mythicant.com/blog/can-chatgpt-do-test-driven-development</link>
      <description />
      <pubDate>Thu, 20 Jul 2023 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>A friend of mine recently pinged me on LinkedIn to have a discussion about AI as it relates to <a href="https://agilemanifesto.org/">agile software development</a>. He referenced a presentation I did that he attended where I demonstrated the steps of test-driven development (TDD) using the Roman numeral kata. (You can see a video of that presentation <a href="/blog/presentation-videos">here</a> or a description of the kata <a href="https://github.com/UtahSC/roman-numeral-kata">here</a>.) To be able to better respond to my friend, I decided to go play with ChatGPT and see how well it would do at TDD.</p>

<p>I consider myself somewhat of an AI skeptic. Well, maybe "AI pragmatist" would be a better term. I know that AI (and more specifically machine learning, which is what most people mean when they say "AI" these days) can do lots of cool things, but that it also is <em>very</em> far from the <a href="https://en.wikipedia.org/wiki/Artificial_general_intelligence">artificial general intelligence</a> that people hope and sometimes think that it is. I went in to this experiment expecting ChatGPT to fail at doing TDD. And it mostly did. But it did surprise me a few times.</p>

<p>What follows is a summary of my interaction with ChatGPT, trying to get it to do test-driven development. You can see the entire exchange <a href="https://chat.openai.com/share/0e958f7b-9efe-49f6-95bd-10313d5beb2f">here</a>.</p>

<h3>Starting Off</h3>

<p>I started off with the simple prompt <code>write code that converts arabic numbers to roman numerals</code>. I didn't start off with great grammar because I wasn't sure how long the conversation would go.</p>

<p>ChatGPT gave me back a reasonable implementation in Python. It even used tuples to store the mapping between Arabic numbers and Roman numerals. Bonus points for knowing the Roman numerals are undefined below 1 and above 3999!</p>

<p><details>
<summary>Initial implementation in Python</summary></p>

<pre><code>def arabic_to_roman(number):
    if not isinstance(number, int) or number &lt;= 0 or number &gt;= 4000:
        raise ValueError("Invalid input: Only positive integers between 1 and 3999 are supported.")

    roman_numerals = [
        ("M", 1000),
        ("CM", 900),
        ("D", 500),
        ("CD", 400),
        ("C", 100),
        ("XC", 90),
        ("L", 50),
        ("XL", 40),
        ("X", 10),
        ("IX", 9),
        ("V", 5),
        ("IV", 4),
        ("I", 1)
    ]

    roman_numeral = ""
    for numeral, value in roman_numerals:
        while number &gt;= value:
            roman_numeral += numeral
            number -= value

    return roman_numeral

# Test the function
try:
    number = int(input("Enter an Arabic number (1 to 3999): "))
    roman_numeral = arabic_to_roman(number)
    print(f"{number} in Roman numerals is: {roman_numeral}")
except ValueError as e:
    print(e)
</code></pre>

<p></details></p>

<p>I then asked it to do it in C#. Not because I have anything against Python, but because when I do the presentation, I usually do it in C#. So this seemed like a more apples to apples comparison.</p>

<p>ChatGPT happily gave me some C# code. Unfortunately, it lost the tuple data structure that I liked. So I asked it to put that back. I assumed it would fail, but it did a great job! And it didn't get confused when I accidentally typed <code>in[]</code> instead of <code>int[]</code>. Good job ChatGPT!</p>

<p>When I do the presentation, I usually go towards a recursive solution, just because the TDD kind of lends itself to that. So I asked ChatGPT to change it's solution to a recursive implementation. No problem. It even added a disclaimer about how a recursive solution "is a neat approach, [but] it might not be the most efficient way to perform this conversion for very large numbers due to the stack space consumed by the recursive calls."</p>

<h3>Getting Serious</h3>

<p>Alright. The easy stuff was over. Now on to the actual test. Did ChatGPT have any idea what test-driven development was? We already had a solution without any tests, which is already not test-driven at all. But even if you don't test drive a solution, if you are sufficiently familiar with a problem you could add tests after the fact that make it <em>look</em> like you test drove the solution. So I went with the prompt <code>now add tests as though the solution were test driven</code>.</p>

<p>Here's what ChatGPT gave me back.</p>

<p><details>
<summary>The response to my initial request for test-driven code</summary></p>

<pre><code>using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class RomanConverterTests
{
    [TestMethod]
    public void TestArabicToRoman_LowerBound()
    {
        int number = 1;
        string expected = "I";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void TestArabicToRoman_UpperBound()
    {
        int number = 3999;
        string expected = "MMMCMXCIX";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void TestArabicToRoman_RandomNumbers()
    {
        var testCases = new (int Number, string ExpectedRoman)[]
        {
            (5, "V"),
            (9, "IX"),
            (42, "XLII"),
            (99, "XCIX"),
            (1984, "MCMLXXXIV"),
            (2023, "MMXXIII"),
            (1000, "M"),
            (1990, "MCMXC"),
            (2000, "MM"),
            (2008, "MMVIII"),
            (3462, "MMMCDLXII")
        };

        foreach (var testCase in testCases)
        {
            string actual = RomanConverter.ArabicToRoman(testCase.Number);
            Assert.AreEqual(testCase.ExpectedRoman, actual);
        }
    }

    [TestMethod]
    public void TestArabicToRoman_InvalidInput()
    {
        int invalidNumber = -1;
        Assert.ThrowsException&lt;ArgumentOutOfRangeException&gt;(() =&gt; RomanConverter.ArabicToRoman(invalidNumber));
    }
}
</code></pre>

<p></details></p>

<p>Okay. Some boundary conditions. That's nice. An assortment of random other cases (which it even named <code>TestArabicToRoman_RandomNumbers</code>). It's a reasonable selection of test cases. If it had chosen to use NUnit instead of MSTest it could have used <code>TestCase</code> attributes instead of creating a collection of test cases and iterating through it. But still, not bad.</p>

<p>But not test-driven at all. I told ChatGPT as much.</p>

<p><code>that doesn't look test driven at all</code>.</p>

<p>ChatGPT politely apologized, said this time it would "rewrite the tests following a test-driven development approach", and then proceeded to give me the exact same code it just gave me.</p>

<p>🤨</p>

<p>I told ChatGPT that it just gave me the exact same code twice in a row. I also pointed out that it said it was going to do test-driven development, explained to me that test-driven development requires writing tests before implementation code, and then explained why it was okay that it didn't write the tests before the implementation code.</p>

<p>ChatGPT politely apologized again. And gave me almost the same code again. It did add a <code>0</code> case and a <code>4000</code> case. That was kind of nice, I guess. But still not test-driven at all. I was starting to lose hope.</p>

<h3>Is There Any Hope?</h3>

<p>When AI solutions start failing me, I like to point out to them that they are failing me. I'm not sure why I do this. Maybe it helps me remember I'm talking to a computer that has no idea what it's doing? Maybe I secretly hope that's what will finally shock the AI in to self awareness? I'm not sure.</p>

<p>But in this case I chose to call out ChatGPT on its failures. When I did, it wrote all the tests, then the complete implementation. The code was almost exactly as it was previously, but it arranged it differently. Sigh.</p>

<p>I called ChatGPT out again. It politely apologized and tried yet again.</p>

<p>But surprisingly, this time it did something different! It actually started with a single test! I started to get excited. Unfortunately, it went down hill quickly after that. After the single test it then gave me a complete implementation, followed by the same basic complete set of test cases.</p>

<p>I responded, <code>You started off writing a single test. I was so hopeful. But then you just implemented the whole thing and then all the tests. I don't think you're well equipped to show an iterative development process.</code></p>

<p>I think mentioning "iterative development" sparked something. The next response <em>actually</em> started out test-driven! I was amazed!</p>

<p><details>
<summary>A single test, followed by an implementation that makes that test pass</summary></p>

<pre><code>using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class RomanConverterTests
{
    [TestMethod]
    public void TestArabicToRoman_LowerBound()
    {
        int number = 1;
        string expected = "I";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }
}

public class RomanConverter
{
    public static string ArabicToRoman(int number)
    {
        return "I"; // This is the minimum code to make the first test pass
    }
}
</code></pre>

<p></details></p>

<p><details>
<summary>A second test and improve the implementation</summary></p>

<pre><code>using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class RomanConverterTests
{
    [TestMethod]
    public void TestArabicToRoman_LowerBound()
    {
        int number = 1;
        string expected = "I";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void TestArabicToRoman_Two()
    {
        int number = 2;
        string expected = "II";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }
}


public class RomanConverter
{
    public static string ArabicToRoman(int number)
    {
        if (number &lt;= 0)
            throw new ArgumentException("Invalid input: Only positive integers are supported.");

        string romanNumeral = "";

        while (number &gt;= 1)
        {
            romanNumeral += "I";
            number -= 1;
        }

        return romanNumeral;
    }
}
</code></pre>

<p></details></p>

<p>This was a larger step after the second test than I personally would have done, but at this point I wasn't complaining! This was by far the best example of test-driven development that I'd gotten out of it.</p>

<p>I asked ChatGPT to continue, hoping it was finally on the right track.</p>

<h3>So Close, Yet So Far Away</h3>

<p>Alas, my hopes were quickly dashed again. Upon responding to ChatGPT with the prompt <code>I stand corrected. That was a great start. Now please finish the rest of the tests and implementation.</code>, it quickly went back to it's old ways of implementing everything in a single pass. </p>

<p>Instead of adding a third test case and improving the implementation slightly as I had hoped, it added test cases for 3 through 5 and provided a complete implementation again. I called it out again.</p>

<p><code>No! You were doing so well. Then you failed.</code></p>

<p>It then gave me test cases for 1 through 10 and a complete implementation. Yet again, I pointed out that was not test-driven development. Yet again, ChatGPT apologized and gave me another response.</p>

<p>This time ChatGPT started off well again. A single test for the 1 case. An implementation that made that test pass. Then it added a second test case, this time for 4. Not a great choice, but if it had actually followed through I would have been okay with it.</p>

<p>Unfortunately, instead of improving the implementation to make the 1 and 4 cases pass, ChatGPT went off the deep end, providing an implementation that handled the <code>I</code> (1) case, the <code>M</code> (1000) case, and the <code>CM</code> (900) case. Where did <em>that</em> come from?</p>

<p><details>
<summary>Where did that come from?</summary></p>

<pre><code>using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class RomanConverterTests
{
    [TestMethod]
    public void TestArabicToRoman_LowerBound()
    {
        int number = 1;
        string expected = "I";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }

    [TestMethod]
    public void TestArabicToRoman_Four()
    {
        int number = 4;
        string expected = "IV";
        string actual = RomanConverter.ArabicToRoman(number);
        Assert.AreEqual(expected, actual);
    }
}


public class RomanConverter
{
    public static string ArabicToRoman(int number)
    {
        if (number &lt;= 0)
            throw new ArgumentException("Invalid input: Only positive integers are supported.");

        string romanNumeral = "";

        while (number &gt;= 1000)
        {
            romanNumeral += "M";
            number -= 1000;
        }

        if (number &gt;= 900)
        {
            romanNumeral += "CM";
            number -= 900;
        }

        // Continue with other Roman numerals...

        while (number &gt;= 1)
        {
            romanNumeral += "I";
            number -= 1;
        }

        return romanNumeral;
    }
}
</code></pre>

<p></details></p>

<p>The best part of this response was that the implementation doesn't even pass the tests! There's a test for the <code>IV</code> (4) case, but the implemenation doesn't address that case at all. Oh, ChatGPT! What were you thinking?</p>

<h3>Finishing Up</h3>

<p>And, of course, the answer was that it wasn't thinking. Because ChatGPT is a large language model, which is a variation of an artificial neural network. It doesn't think. It's an algorithm, a function. It took my input prompts and spit out some output with no understanding. It is a <a href="https://en.wikipedia.org/wiki/Chinese_room">Chinese Room</a>, doing clever things that can appear intelligent, but with no understanding of what it's doing.</p>

<p>After supplying ChatGPT another prompt or two and getting the same, very non-test-driven code, I decided I'd tried enough. It was clear that ChatGPT wasn't really going to generate a test-driven code example because it doesn't really know what test-driven development is.</p>

<h3>Take Aways</h3>

<p>So what can we learn from this? I thought of a few things.</p>

<p>ChatGPT and other AI/machine learning solutions like it can do some really impressive things. It was able to take my prompts and generate a lot of convincing output. Unfortunately, all that output was generated without any understanding.</p>

<p>Which brings me to my next point. The output was often wrong. And wrong in a way that someone new to the subject might not understand. I fear that people wanting to learn something will ask ChatGPT questions and just assume that its answers are correct because they sound convincing.</p>

<p>One of the problems ChatGPT had was that it already "knew" the answer. It knew how to implement an Arabic number to Roman numeral converter. Test-driven development is a design process, not a testing process. If you already have a design then there is little point in using a test-driven approach, other than to add test coverage. ChatGPT demonstrated this marvelously.</p>

<p>I was impressed a couple of times at how ChatGPT was able to refactor some code. I think there may be something valuable there in more powerful automated refactorings than what most of our development tools can do now. Though currently, I wouldn't automatically trust a refactoring that ChatGPT did like I do with most refactoring tools built in to IDEs. I would want to verify any refactorings it did with tests that I had written myself.</p>

<p>And finally, while there may be some types of jobs that could be at risk due to tools like ChatGPT, the job of writing high quality, clean, maintainable, understandable code is not one of them.</p>

<p>Not yet at least.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Lean Software Development Resources</title>
      <link>https://mythicant.com/blog/lean-software-development-resources</link>
      <description />
      <pubDate>Thu, 19 Jan 2023 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>A friend of mine recently asked about resources he could share with his software development team that might help them move from a more Scrum-like workflow to a more lean-inspired workflow. I thought about just sending him a list of ideas, but I figured if I wrote my list down in a blog post that would be a little more permanent and maybe some more people could get some use out of it. This is by no means an exhaustive list, but here it is.</p>

<h2>Books</h2>

<ul>
<li><a href="https://thisislean.com/">This Is Lean</a> - This is a great introduction to lean principles in general. It doesn't go too heavy into math or anything and is overall pretty approachable. It isn't software development specific.</li>
<li><a href="https://www.amazon.com/Principles-Product-Development-Flow-Generation-ebook/dp/B00K7OWG7O">Principles of Product Development Flow</a> - This goes into lots more detail and is a much more in-depth read. There's some math that initially can look a little scary, but it's not too bad. This book focuses on lean product development, but isn't software specific.</li>
<li><a href="https://www.amazon.com/Implementing-Lean-Software-Development-Concept/dp/0321437381">Implementing Lean Software Development</a> - The authors of this book actually coined the term "lean software development". This is a great book and is specific to software.</li>
<li><a href="https://www.amazon.com/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B078Y98RG8">The Phoenix Project</a> and <a href="https://www.amazon.com/Unicorn-Project-Developers-Disruption-Thriving-ebook/dp/B07QT9QR41">The Unicorn Project</a> - Maybe not strictly focused on lean, but these books definitely talk about things like reducing knowledge silos, flowing value to customers more quickly and frequently, and on reducing waste. Plus, they in are in a more story-based format, which can be easier to read than some other, more technical books.</li>
<li><a href="https://theleanstartup.com/">The Lean Startup</a> - This book has some great thoughts on lean, especially as applied to smaller, more startup-type contexts.</li>
</ul>

<h2>Presentations</h2>

<ul>
<li><a href="https://www.youtube.com/watch?v=U_HgMduuE5s&amp;list=WL&amp;index=40">Competing On The Basis Of Speed</a> - This is a great overview of lean software development principles, given by Mary Poppendieck, one of the authors of Implementing Lean Software Development.</li>
<li><a href="https://www.youtube.com/watch?v=TwasxNk1824">The Lean Mindset</a> - Inspired by <a href="https://www.youtube.com/watch?v=C13JC_YP2Q8&amp;t=391s">The Agile Mindset</a> (Linda Rising) and <a href="https://www.amazon.com/Mindset-Psychology-Carol-S-Dweck-ebook/dp/B000FCKPHG">The Growth Mindset</a> (Carol Dweck), again presented by Mary Poppendieck. This one talks about some of the organizational impacts of thinking and working in a lean fashion.</li>
<li><a href="https://www.youtube.com/watch?v=3f1JebvRnOw">No Estimates</a> - Not strictly lean, but spending a lot of time creating estimates can be a significant form of waste, something that lean focuses on reducing. Plus Woody Zuill is just awesome.</li>
</ul>

<h2>Activities</h2>

<ul>
<li><a href="https://getkanban.com/?variant=4565683971">getKanban</a> - This is an awesome board game you can play with a group to help demonstrate some lean principles and spark discussion. Unforunately, it's really intended for coaches and consultants, so the latest version costs $550! And as I'm writing this it's sold out. So you probably shouldn't get that version. They do have a free version that you can download and probably still get quite a bit of value out of, but it's less streamlined and polished than the latest version.</li>
<li><a href="http://www.kanbanboardgame.com/">Kanban Board Game</a> - getKanban sound interesting, except for the $550 part and the being sold out part? How about a free online version instead? You do have to sign up for an account to play, but it's free. This isn't exactly like the physical board game, but it is a much more economical option.</li>
<li><a href="https://agilesimulations.co.uk/no-estimates/?walkThrough">No Estimates</a> - One online option not enough for you? How about another one? Try both online options out to see which you like better.</li>
<li><a href="https://www.youtube.com/watch?v=Dr67i5SdXiM">Envelope stuffing exercise</a> - There are some hands-on activities that can help demonstrate some lean practices, like reducing batch sizes. The envelope stuffing exercise is one of those activities. This video is a quick demonstration with a single person, but you can expand the exercise out into multiple people and even multiple teams if you want.</li>
<li><a href="https://www.youtube.com/watch?v=JoLHKSE8sfU">One Piece Flow versus Batch Processing</a> - A nice, quick little video showing how batch size can impact the speed of delivery.</li>
<li><a href="https://www.youtube.com/watch?v=fh4nkQnWL6I">Coin Game</a> - One way to do the one piece flow exercise shown in the previous video is with a coin flipping game. This video shows an example of how that game can be facilitated.</li>
</ul>

<p>And one last great resource, another list of resources! <a href="https://www.youtube.com/channel/UCgt1lVMrdwlZKBaerxxp2iQ">The Mob Mentality</a> folks have put together <a href="https://trello.com/b/1lfMkCOh/software-profession-resources">an amazing list</a> of software development resources. Many of them focus on mob programming, but there are also lots of resources for lean, lean-related topics, and various other software development topics.</p>

<p>Again, this is by no means an exhaustive list. But hopefully it has some useful resources that can help get some conversations started on my friend's team. And maybe some other people will find it useful as well.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Becoming a Keyboard Sith Apprentice</title>
      <link>https://mythicant.com/blog/keyboard-sith-apprentice-activity</link>
      <description />
      <pubDate>Thu, 18 Aug 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>The keyboard and mouse are both powerful input tools.
Back in the olden days, all people had was a keyboard.
(I'm sure someone even older than me will chime in about only having punch cards and switches as input devices, but that's not part of this story.)
These days you can do almost everything with mouse interaction.
Sometimes there are things you can <em>only</em> do with a mouse.</p>

<p>The sweet spot in computer interaction is probably somewhere in-between, some keyboard interaction and some mouse interaction.
But given how common mouse interaction is, sometimes people don't know how to do certain things with a keyboard, even it it would be faster and easier.</p>

<p>This post contains an activity to help people practice interacting with their computer using a keyboard.
Should you always interact with your computer this way?
No, probably not.
But sometimes an effective way to practice something is to turn it all the way up to 11 and see what happens.
That's what this activity is going to be.</p>

<h2>Keyboard Jedi</h2>

<p>But first, some history.
A long time ago, on a computer far, far away there was a program named Keyboard Jedi.
It was written by Roy Osherove.
You can read about it and download the code <a href="https://osherove.com/blog/2007/6/3/train-to-be-a-keyboard-master-with-keyboard-jedi.html">here</a>.
Keyboard Jedi could show keyboard shortcut keypresses (great for presentations).
It could also lock the mouse in Visual Studio so you could practice going mouseless just there.
It was a great app.</p>

<p>But sadly, Keyboard Jedi was written back in the pre-Windows Vista days before Microsoft switched to 64-bit and broke everything.
When I switched to Windows Vista then Keyboard Jedi no longer worked.
There were some work arounds, but they were a lot of work.</p>

<h2>Keyboard Sith</h2>

<p>I really liked Keyboard Jedi, but I couldn't use it anymore.
So I did what any self-respecting software engineer would do.
I wrote my own replacement!
I called it Keyboard Sith.
You can read more about it and download it <a href="becoming-a-keyboard-sith">here</a> (though it's Windows only).</p>

<blockquote>
  <p>As a side note, in case you're not familiar with the terms "Jedi" and "Sith", they come from Star Wars. In Star Wars, the good space wizards with laser swords are called "Jedi". The evil ones are called "Sith".</p>
</blockquote>

<p>Keyboard Sith is a little lighter weight than Keyboard Jedi.
For example, it doesn't show keypresses.
And it locks the mouse completely, not just for Visual Studio.
Simple, effective, powerful, and slightly evil.
Just like the Sith.</p>

<p>For this activity, we won't be using Keyboard Sith (unless you want to).
But at least now you know where the title of the blog post came from.
And because this is intended to be an introductory activity, we'll just work on becoming Keyboard Sith apprentices, rather than full on Keyboard Sith lords.</p>

<h2>The Activity</h2>

<p>But enough history.
On to the activity.</p>

<p>The goal of this activity is to get better at using keyboard shortcuts.</p>

<h3>Getting Started</h3>

<p>If you're using a mouse, turn it upside down.
Not on it's back, but so that the "front" (the part that usually points away from you) is pointing towards you and the "back" (the part that usually points towards  you) is pointing away from you.
If you're using a trackpad, put a piece of paper or your phone or something over the trackpad.</p>

<p>The purpose of doing all of this is so you don't unconsciously reach over and use your mouse or trackpad.</p>

<p>If you want to be super hardcore you can unplug your mouse or disable your trackpad, but you probably don't want to do that because you'll probably need to cheat.</p>

<h3>Cheating</h3>

<p>We're going to do a few tasks without using your mouse/trackpad.
But if you haven't done these things using only the keyboard before it will probably be really hard.
Or impossible.
So you'll probably need to cheat.</p>

<p>That's okay.
If you can't figure out how to do something, it's okay to use your mouse/trackpad.
But only use it enough to find out how to do whatever you're stuck on with your keyboard.
In some applications you can mouse over a button to show its keyboard shortcut.
Maybe you need to go Google how to do something with the keyboard.
All that is okay to learn what the keyboard shortcut is, but make sure to turn your mouse back around or cover your trackpad back up and do the actual task using just the keyboard.</p>

<h3>The Tasks</h3>

<p>Okay, now that you have your mouse or trackpad in a state where it's hard to use, and you know how to cheat if you need to, it's time for your actual tasks.
Do the tasks one at a time.
You can do them in order, but if one is too hard to do you can skip to the next one.
Remember that you can cheat if you need to in order to learn the keyboard shortcuts, but then use the keyboard shortcuts to actually do the task.
Also remember to disable your mouse or keyboard again.</p>

<p>Good luck!</p>

<ul>
<li>Task #1 - Open a web browser go to google.com.</li>
<li>Task #2 - Create a text file somewhere on your computer, put the text "Keyboard Sith" in it, and save it.</li>
<li>Task #3 - Find out how much free storage space your hard drive has.</li>
<li>Task #4 - Write a short email and send it.</li>
</ul>

<p>If this is your first time, that list will probably keep you busy for a little while.
But if you need an extra challenge here are some additional tasks you could try.</p>

<ul>
<li>Bonus Task #1 - Open a web browser, go to mythicant.com, and find and read a blog post that has the word "Mario" in it.</li>
<li>Bonus Task #2 - Disconnect and reconnect your network connection. This could be turning off your wifi and turning it back on or connecting to a different network.</li>
<li>Bonus Task #3 - Start a new project. If you're a software developer, create a brand new "hello world" project and run it. If you're not a software developer, try to create a brand new "hello world" project for your area of expertise.</li>
<li>Bonus Task #4 - Lock, shutdown, or restart your computer.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Mega Man Quotes CLI v1.1</title>
      <link>https://mythicant.com/blog/mega-man-quotes-cli-v11</link>
      <description />
      <pubDate>Wed, 22 Jun 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I posted about <a href="mega-man-quotes">Mega Man quote</a> in general previous.
Just a quick update.
v1.1 of the <a href="https://github.com/theparticleman/MegaManQuotesCli/releases/tag/v1.1">CLI tool</a> is now released.</p>

<p><img src="/images/mega-man-quotes-cli-v11.png" alt="Mega Man Quotes CLI v1.1" /></p>

<p>The big change is that now, in addition to printing out a quote, the author's name, the source if available, and a snazzy picture of Mega Man, it now also will print out a permalink to the quote.
This hopefully makes it easier to share quotes you like with your friends and co-workers.</p>

<p><a href="https://megamanquotes.com">Visit megamanquotes.com</a></p>

<p><a href="https://megamanquotes.com/api">Read the documentation for the API</a></p>

<p><a href="https://github.com/theparticleman/MegaManQuotesCli/releases/tag/v1.1">Download the Mega Man Quotes CLI v1.1</a></p>

<p><a href="https://github.com/theparticleman/MegaManQuotesCli">Get the source code for the Mega Man Quotes CLI</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Coding with Jon and Mike</title>
      <link>https://mythicant.com/blog/coding-with-jon-and-mike</link>
      <description />
      <pubDate>Tue, 14 Jun 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I think good software development practices can make a big difference when creating software. 
I'm thinking of things like test driven development, pair and mob programming, and automated continuous integration and continous delivery pipelines to name a few.</p>

<p>But one challenge I've noticed with having people use these types of practices is that it can be hard to really "get" them until you see them in action.</p>

<p>For example, one time while attending the <a href="http://utahsc.org">Utah Software Craftsmanship</a> group, another developer and I paired on a coding exercise.
This particular developer had a few years of experience, and had attended the group a few times.
But he didn't have a lot of exposure to test driven development.
During the coding exercise I tried to guide us through a test driven path to solving the problem.
I didn't do anything wild or crazy, just tried to follow the <a href="http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd">rules of TDD</a> (since practicing was one of the purposes of the coding exercise).</p>

<p>At the end of the coding exercise the other developer thanked me.
He said that through the things I did during the coding exercise he had finally started to understand what test driven development was all about.
Because he saw it, it was easier for him to "get" it.</p>

<p>That experience stayed with me.
I thought several times about creating a series of videos or something to help people see things like test driven development in practice to help make it easier to "get" them.
Unfortunately, I never got around to making those videos.</p>

<p>Fortunately, my friend <a href="http://blog.softwareontheside.com/">Mike</a> and I <em>did</em> get around to making some of those videos!</p>

<p>Mike and I had an experience similar to the one I mentioned above with a coding exercise.
We decided to pair on a coding exercise together (again, at the Utah Software Craftsmanship group).
We didn't introduce each other to test driven development, but had a good time working on the exercise.
At the end of the meeting, everyone got back together and discussed how the exercise had gone.
Mike and I talked about how our experience went.
As we did, one of the other attendees said something like, "I wish I could have been a fly on the wall during that pairing session!"</p>

<p>That got us thinking that we should find a way to let people be that fly on the wall because they might get some value from it.
So we created a YouTube channel, <a href="https://www.youtube.com/channel/UCPeEnPwRkqmF-_1rCbE7-lA/featured">Coding with Jon and Mike</a>.</p>

<p>So far we have about half a dozen videos.
About half are us doing test driven development.
The other half are us working through a refactoring project (another great software development practice).
And since it's both of us, they are obviously examples of pair programming in action.</p>

<p>If this kind of thing sounds interesting to you, give a few of the videos a watch.
Let us know what you think.
Let us know what you'd like to see more of and what you'd like to see less of.</p>

<p>Hopefully being able to see these videos will help some people be able to "get" some of these extremely helpful software development practices.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Mega Man Quotes</title>
      <link>https://mythicant.com/blog/mega-man-quotes</link>
      <description />
      <pubDate>Mon, 18 Apr 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>At various times in the past I've used quotes from industry experts to teach and inspire others, as well as spark discussions with my co-workers.
The last few years my sharing has taken the form of Slack bots, primarily one named Mega Man.
I've used Mega Man to share a variety of software development and software craftsmanship-related quotes.</p>

<p>Some people have been ambivalent about Mega Man and the quotes he's shared.
One or two people have been negative about it.
(Remind me to tell you the story sometime about the time someone called me, the guy with two black kids, a racist because of one of the quotes Mega Man shared. Good times.)
But overall the responses to Mega Man and the quotes he's shared have been pretty postive.</p>

<p>While I've found my Mega Man Slack bot to be an effective tool for sharing knowledge, I've occasionally run into some technical challenges.
For example, over the years I've stored the quotes Mega Man shares in a couple of different formats.
Mostly I've done whatever was expedient to the code I was writing at the time.
But I've ended up with several different copies and several different versions of the quotes.
Having multiple copies in multiple formats has certainly made it much more difficult to update my list of quotes effectively.</p>

<p>And what kind of software developer would I be if I didn't try solving all my problems by writing code?</p>

<p>Introducing <a href="https://megamanquotes.com">Mega Man Quotes as a Service</a> (MMQaaS)!</p>

<p><img src="/images/mega-man-quotes-web.png" alt="Mega Man Quotes website" /></p>

<p>I now have a central place to put all my quotes.
It's exposed via an HTTP+JSON API so I can access the same list of quotes from different apps that I write.
So far <a href="https://megamanquotes.com">megamanquotes.com</a> (which is obviously a web app) uses the API, as does the command line tool I wrote.</p>

<p><img src="/images/mega-man-quotes.gif" alt="Mega Man Quotes cli" /></p>

<p>Now I just need to go update my existing Slack bots to use this new API so that I can reap all the benefits I just professed to get from this new code.</p>

<p><a href="https://megamanquotes.com">Visit megamanquotes.com</a></p>

<p><a href="https://megamanquotes.com/api">Read the documentation for the API</a></p>

<p><a href="https://github.com/theparticleman/MegaManQuotesCli/releases/tag/v1.0">Download the Mega Man Quotes CLI</a></p>

<p><a href="https://github.com/theparticleman/MegaManQuotesCli">Get the source code for the Mega Man Quotes CLI</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>This is Fine</title>
      <link>https://mythicant.com/blog/this-is-fine</link>
      <description />
      <pubDate>Fri, 01 Apr 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>I'm a big fan of KC Green's <em>This is Fine</em> comic.
You should <a href="http://gunshowcomic.com/648">check it out</a> if you're not familiar with it.
You should also go visit <a href="http://kcgreendotcom.com/index.html">KC's site</a> and support him if you feel so inclined.</p>

<p>In my <a href="grumble-grumble">last post</a> I wrote about a command line tool inspired by The Legend of Zelda.
I made another one, but this time inspired by the <em>This is Fine</em> comic!</p>

<p><img src="/images/this-is-fine.gif" alt="This is Fine command line tool" /></p>

<p>Pretty much the same as the <code>grumble</code> command line tool, but this time with 100% more This is Fine.
I used <a href="https://spectreconsole.net/">Spectre.Console</a> again, but this time I figured out a way to use the CanvasImage but still draw the image centered on the screen.
It was much quicker to just edit the image and then draw it instead of having to translate every pixel into code.
Maybe I'll go back and refactor <code>grumble</code> to do the same thing...</p>

<p>On some of the drawable items in Spectre.Console there is an extension method to easily center things.
Not so with CanvasImage (or at least not that I've found so far).
It may still be worth submitting a pull request for that.</p>

<p>This time in addition to providing just a Windows version, there are also MacOS and Linux versions.
I don't have a great way to test them, so there are probably issues.
But it's a start at least.
If you find any issues with them, <a href="/contact">let me know</a>.</p>

<p><a href="https://github.com/theparticleman/ThisIsFine/releases">Download This is Fine command line tool v1.0</a></p>

<p><a href="https://github.com/theparticleman/ThisIsFine">Get the source code</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Grumble, Grumble...</title>
      <link>https://mythicant.com/blog/grumble-grumble</link>
      <description />
      <pubDate>Fri, 18 Mar 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>In the original Legend of Zelda game on NES (you may have noticed I have somewhat of an <a href="/fable-of-griselda">interest in the game</a>), the seventh dungeon in the game was a little different than all the others.
At a certain point in the dungeon, rather than a normal room with enemies and puzzles, there is a room with a single character who just says, "Grumble, grumble...".
He can't directly be interacted with, and there are no other clues about how to get past this character.
But in order to complete the dungeon and the game you have to get past this character.
What to do?</p>

<p><img src="/images/grumble-grumble-1.png" alt="Hungry Goriya" />
(Screenshot from <a href="https://www.zeldadungeon.net/the-legend-of-zelda-walkthrough/level-7-the-demon/">zeldadungeon.net</a>)</p>

<p>It turns out the secret is to give the character (known in Legend of Zelda guides and walkthroughs as the <a href="https://zelda-archive.fandom.com/wiki/Hungry_Goriya">Hungry Goriya</a>) some food.
I assume the way you're supposed to know this is to interpret "Grumble, grumble..." as the character's stomach rumbling because he's hungry?
I think it was one of the more unclear puzzles in the game, but the memory of the experience has stuck with me.</p>

<p>Yesterday at work, my team and I were updating some Javascript dependencies in our code.
Updating Javascript dependencies is one of those things in software development that's totally fine and doable, but seems way more complicated and difficult than it needs to be.
It isn't my favorite thing to do, but it's what we needed to do.
Doing it put me in a mood where I wanted to subtly complain about the task in order to make getting through it less obnoxious. I wanted to grumble about it.</p>

<p>I thought back to the Hungry Goriya.
His grumbling was apparently due to hunger.
But was he perhaps subtly complaining about his situation as well in order to help him get through his current challenge?</p>

<p>I commented to my team that I needed a command line tool for when I'm in that kind of grumbly mood.
I want to be able to type <code>grumble</code> in my terminal window and the tool would print out the Hungry Goriya to help me commiserate with my challenges.</p>

<p>So last night I made that command line tool.</p>

<p><img src="/images/grumble.gif" alt="Grumble command line tool" /></p>

<p>Being able to run the tool in my terminal window whenever I need it makes me happy, as did the process of creating it.
It's written in C# and uses the ability that more recent versions of .NET have to publish to a single, self-contained executable.
Even with compression and dependency tree shaking it's still around 12MB, which is kind of ridiculous for what it is.
But it also only took an hour or something to put together.
And I got to write it in C# instead of some other language I'm less familiar with.
To me that's worth a few extra megabytes in executable size.</p>

<p>I used <a href="https://spectreconsole.net/">Spectre.Console</a> to easily print out the <a href="http://www.figlet.org/">Figlet</a> text.
Spectre.Console also has the ability to read an image and print it to the console.
I was going to use that, but I wasn't able to center the image horizontally.
Maybe I'll have to open an issue or PR on their Github page or something.
But Spectre.Console does have an image canvas feature that makes drawing ASCII-based images like this easier.
I ended up using that, and it worked pretty well.
I'm just glad the sprites for Legend of Zelda aren't any bigger than they are.</p>

<p>So what's the take-away from this experience?
Well, for me I think the take-away is that a little grumbling from time to time can be healthy.
Acknowledging that we're going through a challenge can help make that challenge easier to get through.
It's obviously easy to go too far and let grumbling turn into pure negativity.
But as far as I'm concerned, a little grumbling now and then can be both healthy and helpful.</p>

<p><a href="https://github.com/theparticleman/Grumble/releases/tag/v1.1">Download Grumble command line tool v1.1</a></p>

<p><a href="https://github.com/theparticleman/Grumble/releases/tag/v1.0">Download Grumble command line tool v1.0</a></p>

<p><a href="https://github.com/theparticleman/Grumble">Get the source code</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>A Little Buddy - Web Edition</title>
      <link>https://mythicant.com/blog/a-little-buddy-web-edition</link>
      <description />
      <pubDate>Tue, 08 Feb 2022 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Several years ago, I made a little desktop companion app based on <a href="a-little-buddy">Mega Man</a>. It's fun to run sometimes and have Mega Man run around my desktop, especially if I'm sharing my screen on Zoom or the like during these pandemic times.</p>

<p>Unfortunately, it's a little hard for other people to enjoy Mega Man. I wrote it in 2008 using .NET Framework, so it's not cross platform at all. It does run on Windows 11, but you have to download the correct version of the .NET Framework (which happens automatically when you try to run the executable, but it's not a great user experience).</p>

<p>Fortunately, we do live in an age when making things in a browser sucks a lot less than it used to. And I am on something of a <a href="https://fableofgriselda.com">web kick</a> lately. So I remade my little Mega Man desktop buddy to run in a browser!</p>

<p>You can check him out on the <a href="/">home page</a> for this site. I also put him on the <a href="/blog">main blog page</a>. I thought it might be nice for people scrolling through my list of blog posts to have a companion while they do so. I might put him on other pages too. We'll see.</p>

<p>Oh, yeah! He's also on the page for <a href="a-little-buddy-web-edition">this blog post</a>. That seemed appropriate. If you want to give him a break for a bit you can click the button in the upper right corner with his face on it.</p>

<p><a href="/"><img src="/images/a-little-buddy-web-edition-1.png" alt="Mega Man buddy screenshot"></a></p>

<p>Some things I learned (or maybe remembered) while making this:</p>

<ul>
<li>I wanted all the code for this to be in a single <code>.js</code> file. I wanted to just be able to include it on a page and the script would do everything it needed, including having all the images. Embedding base64 encoded images in a Javascript file is pretty easy. I wouldn't recommend always using that method for images, but in this case it worked well.</li>
<li><code>position: fixed</code> is your friend for this kind of stuff.</li>
<li>Creating HTML elements and adding them to the DOM programmatically isn't my favorite thing, but really isn't that bad in modern vanilla JS.</li>
<li>Using local storage in vanilla JS is pretty easy too.</li>
<li>The responsive/mobile dev tools in Chromium can get in to a weird state where they just don't work right. They report viewport sizes incorrectly and all kinds of stuff that wreaks havoc when trying to get something like this working properly.</li>
<li><code>imageRendering: pixelated</code> is my new favorite CSS property.</li>
</ul>

<script async src='/megaman.js'></script>
]]></content:encoded>
    </item>
    <item>
      <title>Presentation Videos</title>
      <link>https://mythicant.com/blog/presentation-videos</link>
      <description />
      <pubDate>Fri, 29 Oct 2021 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>Presenting is a thing I've been doing for the last 10 or 15 years. Maybe longer, depending on exactly how you count. I think it's a great way to share with others and give back to the community (in my case mostly the software development community). It's something I'd <a href="/blog/getting-started-presenting">encourage everyone to do</a>. Whether you're an expert or just getting started, you have something to share.</p>

<p>The last year or two have necessitated a lot of changes, and my presentation experiences are no exception. While in the past I've presented mostly at in-person conferences, the last year or two has meant presenting exclusively at virtual conferences. Virtual conferences have some drawbacks compared to in-person conferences, but they have some advantages too. One advantage is that many times the presentations are recorded and can be watched later.</p>

<p>I've recorded several presentations the last year or two, so I thought I'd post them here in one big list to make them easier to find. Enjoy!</p>

<h3>One Year of Remote Mob Programming</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/2jxO8RYvmso" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>This presenataion was at XP 2021. I share some of my experiences doing remote mob programming for a year. You can read the white paper that goes along with the video <a href="https://www.agilealliance.org/resources/experience-reports/one-year-of-remote-mob-programming/">here</a>.</p>

<h3>"Microservices Will Save Your Life" and Other Lies</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/54WYirprmGA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>This presentation was at Agile 2021. I had fun refuting some claims about software development I've heard throughout my career. I gave a longer version of this presentation at Big Mountain Data &amp; Dev 2020. You can watch that version <a href="https://www.youtube.com/watch?v=Mwjn6nrSI2M">here</a>.</p>

<h3>TDD - It's About More Than Just the Tests</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/GAamdFa9VPw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>I've given this presentation a few times, but this version was for Reliable Web Summit. It's an introduction to test driven development using a little explanation but mostly using a live coding example.</p>

<h3>The Legend of Zelda, ASCII Art, Hexagonal Architecture, and You</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/cqHRfBpekpQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>This presentation is part experience report, part code review, and partly an introduction to several software architecture patterns. It's based on my experience converting <a href="https://fableofgriselda.com/">Fable of Griselda</a> from a console application to a web application.</p>

<h3>Absolute Beginner's Guide to Docker</h3>

<iframe width="560" height="315" src="https://www.youtube.com/embed/db5jLi6BnaI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

<p>I've given this presentation a few times, but this version was as a Jetbrains webinar. The Jetbrains folks were awesome, and we got a lot of good questions and interaction as part of the webinar.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A Website Reborn</title>
      <link>https://mythicant.com/blog/a-website-reborn</link>
      <description />
      <pubDate>Sun, 23 May 2021 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>It's all GoDaddy's fault.</p>

<p>Back in the day when I used GoDaddy as a domain name registrar they also had a blogging service. It was terrible. But it supported Windows Live Writer, which meant I didn't have to author blog posts through a terrible web UI. That seemed like a reasonable trade-off at the time.</p>

<p>Eventually I moved all my domain names from GoDaddy to something less horrible. Maybe I'll write a blog post about that some time. But when I stopped using GoDaddy I lost access to it's blogging platform. Not that I was particularly sad about that. Except that I no longer had a blog and any SEO juice I had acquired was now gone.</p>

<p>For several years I thought about getting around to resurrecting my blog. But I wanted a site where I could have blog posts <em>and</em> have various dedicated pages for games and such. I never found a system or platform that really worked well for me, so my blog stayed dead.</p>

<p>Recently static website generators have become a thing. I've used a few, like Hugo and Jekyll. I like them in theory, but even those are kind of overkill. I just want some simple, hand-crafted, artisanal HTML and CSS. Is that too much to ask?</p>

<p>So like any self-respecting software developer, when it seems like the existing solutions are too complicated, what did I do? I made mine own that's arguably more complicated, of course!</p>

<p>This site (in it's current incarnation at least) is now a generated static website. You can check out the code <a href="https://github.com/theparticleman/theparticleman.github.io">here</a>. You probably don't want to use it, since it's specifically for my use case. But, you know, if that's your thing, go for it.</p>

<p>I still have the posts from the previous incarnation of my blog. Those posts aren't all here right now, but I plan to bring them over as I have time. I'll also probably bring over some posts that I wrote for the <a href="https://www.pluralsight.com/tech-blog">Pluralsight Tech Blog</a> when I worked there.</p>

<p>Anyway, that's a bit of a bridge between the old content that will live here and whatever new content I end up putting here. Hopefully it's not all too confusing.</p>

<p>And if it is too confusing, or wrong, or terrible in any other way, feel free to blame GoDaddy.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Getting Started Presenting</title>
      <link>https://mythicant.com/blog/getting-started-presenting</link>
      <description />
      <pubDate>Sat, 19 Oct 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/getting-started-presenting/">Pluralsight Tech Blog</a></em></p>

<p>Getting up in front of a group and talking about something for any period of time can be scary. But it can also be a great way to share your knowledge, to increase your knowledge, and to help others. In the tech world there is so much to know and learn, it’s basically impossible for an individual to learn everything they need to know on their own. Giving and receiving presentations can be a great way to share certain types of ideas, especially in the tech world. In this blog post I’m not going to try to convince you that you should present (though I would encourage considering it). The goal of this blog post is to give you some ideas on how to get started if you have some interest but no experience yet.</p>

<h3>What to Talk About?</h3>

<p>The first challenge you may have when getting started presenting is deciding what to talk about. Deeply technical presentations or presentations given by people with years and years of experience can be very valuable. But they aren’t the only type of valuable presentation. Just because you don’t know everything about a topic doesn’t mean you can’t give a presentation on it. And just because you don’t have years of experience doesn’t mean you don’t have something valuable to share with the world.</p>

<p>For me personally, I find that I do better at presenting when the topic is something that interests me, something I have a lot of experience with, or something that I feel strongly about. If you want to present at a specific event you might have to choose a topic that aligns well with that event, but otherwise I would recommend starting with something that is important to you.</p>

<h3>Start Small</h3>

<p>Going from zero experience to doing an hour long presentation in front of a room full of people may be a bigger initial step than you want to take. (Though if you’re comfortable making that big of a step, go for it!) It can be helpful to take some smaller steps first. Here are a few ideas of smaller steps that might help:</p>

<ul>
<li>Blog posts - If you want a chance to sort through your thoughts at your own pace without the pressure of having a bunch of people staring at you, a blog post can be a great way to do that. Sometimes before doing a presentation I’ll write my ideas down as a blog post to organize my thoughts and to make sure I have enough interesting things to talk about on the topic. If your company (or another organization you’re affiliated with) has a blog (like this one) you could try writing your post there. Or you can always start your own blog. Even if no one reads it you can have a place to write down your ideas. </li>
<li>YouTube - This isn’t one that I’ve tried, but I have talked to other people who put together their own YouTube channel with short versions of things they want to present on. This does get you in front of people (assuming someone watches your videos), but it’s not in real time. It gives you the opportunity to do several takes at what you want to say. That both gets you more practice presenting and allows you editting options after the fact.</li>
<li>Mentoring - For some people, talking to one person at a time in an informal setting can be a lot less intimidating than talking to a room full of people in a formal presentation setting. If that sounds like you, maybe consider finding a person or two that you can help mentor. They can be your co-workers or people you meet at community events. This can also be a great way to help out people new to the tech world.</li>
<li>Lightning talks - Preparing enough material to talk about for an hour can be a lot different than preparing enough material to talk about for 5 minutes. Lightning talks can be a great way to get a little bit of presentation experience before trying something with a bigger commitment. If your work has a venue where volunteers can sign up to give lightning talks that can be an easy way to get started. Many meet ups and user groups set time aside during their meetings for lightning talks. If neither of those are options for you, getting a group of coworkers or friends together might be an option.</li>
</ul>

<p>This is by no means an exhaustive list. If you’re feeling nervous about doing a large presentation in front of a large group of people, see if there are ways you can reduce the scope of what you’re presenting or who you’re presenting to. That might help you feel less anxious.</p>

<h3>Take the Plunge</h3>

<p>When you do decide you want to do a longer presentation there are a lot of options you could explore. Here are a few:</p>

<ul>
<li>Company events - Does your company have one or more venues where you could present? Many employers have some type of brown bag or other type of learning program where internal presenters share materials with their co-workers. Others have a quarterly (or annual or some other cadence) conference-like event. If your company has something like this you might consider trying to present at this type of event. Depending on your company, these events might be smaller than other events. And you might be presenting to people you work with every day instead of total strangers (which I guess could be a pro or a con). If your company doesn’t have something like this but it sound interesting to you, you might consider trying to start it.</li>
<li>User groups - Many areas have meet up or user groups that have presentations. Some are technology specific (e.g. Node.js, Android development, .NET, etc.) while others are more general (e.g. software development, machine learning, software craftsmanship/crafters, etc.). Many of these groups have a presentation as part of their regular meetings. If they do, they are probably always on the look out for people to give presentations. If you don’t already attend a meeting or two like this, try to find one that fits your interests and schedule. If you do attend one, talk to the organizers about what it would take to do a presentation.</li>
<li>Local conferences - There might be a conference across the country that fits exactly what you want to present. If so, try to present at that conference. But travel and hotel accomodations as well as time away from work can make that type of presentation experience more complicated. It’s also worth looking to see if there are any local conferences near where you live that accept volunteer presenters. Some local conferences explicitly try to involve new presenters. Many local conferences are free or lower cost, so attendees may be a bit more forgiving than those at a conference that costs thousands of dollars to attend.</li>
</ul>

<h3>A Couple More Tips</h3>

<p>Whether you’re taking a smaller step to get prepared to present or doing a presentation at a user group or a conference, there are a few things that I’ve found helpful.</p>

<p>Most conferences or user groups have some sort of call for papers (CFP) or request for proposals (RFP) process. If you want to present at one of these event find out what the process is, and most importantly, when the deadlines are. It can be discouraging to get all excited about submitting a proposal to a conference only to find out you missed the submission deadline by a few weeks or months and will have to wait for another year to submit another proposal. If you can talk directly to one of the event organizers they can probably give you that info. Hopefully the website for the event has that information. If the website doesn’t have information about the submission process but does have contact information, try using that contact information to ask about the process.</p>

<p>Figure out what helps you feel comfortable. For me, being able to go over my presentation multiple times by myself (to figure out wording and timing and everything) helps me feel a lot more comfortable. Practicing on your own might be what helps you feel more comfortable. Practicing in front of a small group first might help. Having good notes that you can reference might help. Integrating your favorite internet meme or pictures of your cat might help. Try to find things that will help you feel more comfortable and confident when you’re presenting.</p>

<p>Find other people who are also interested in presenting. If you have coworkers or friends or people you meet at user groups or conferences who are interested in presenting, get together to talk with them. They might know about good presenting opportunities that you haven’t heard about. If all else fails, go to a user group or a conference and ask one of the presenters for ideas and tips. Most presenters I know are more than happy to help out. That’s usually why they are presenting.</p>

<p>If you are new to presenting, and especially if you are new to software development, don’t feel like you have to be an expert on something in order to share useful information about it. Odds are if you just learned something that you found useful that there are a bunch of other people who would find it useful too. And don’t discount the positive impact that an experience report can have on others who are just a step or two behind you in their journey. Don’t try to pretend that you know more than you really do, but don’t undervalue the experiences you’ve had and the things that you have learned. The <a href="https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect">Dunning-Kruger</a> effect is real, but so is <a href="https://en.wikipedia.org/wiki/Impostor_syndrome">Impostor Syndrome</a>.</p>

<p>And finally, when you do give a presentation somewhere, make sure you actually can give your presentation. If you need to hook up your computer to a projector, make sure you have any necessary dongles. If you’re not sure what type of hookup will be available, ask someone where you will be presenting. If you will need internet access for your presentation, make sure you know how you’re going to get it and that it will be high enough speed and bandwidth for your needs.</p>

<h3>Wrap Up</h3>

<p>Presenting on technical topics can be very rewarding. It can be a great way to help others and to learn more about topics you’re interested in. But it can also be scary. Hopefully this blog post has given you a few ideas about how to start making presenting a little less scary.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Different Types of Unit Tests</title>
      <link>https://mythicant.com/blog/different-types-of-unit-tests</link>
      <description />
      <pubDate>Fri, 12 Apr 2019 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/different-types-of-unit-tests/">Pluralsight Tech Blog</a></em></p>

<p>There are lots of different types of tests. There are lots of different types of automated tests. In this post we’ll talk about unit tests, specifically a few different types of unit tests and when you might want to use each. We’ll be using examples in C# using Nunit.</p>

<h3>Example Code</h3>

<p>We’ll use some example code for parts of the discussion in this post. This code takes a username and password and, assuming they match the stored username and password, will generate a signed JWT for the user and store it in a cookie.</p>

<pre><code>public class SignInCommand
{
    //Constants and class variables removed for brevity.

    public SignInCommand(ICookieHelper cookieHelper, ITokenGenerator     tokenGenerator, IUserRepository userRepository, IPasswordHasher     passwordHasher)
    {
        this.cookieHelper = cookieHelper;
        this.tokenGenerator = tokenGenerator;
        this.userRepository = userRepository;
        this.passwordHasher = passwordHasher;
    }

    public async Task&lt;bool&gt; Execute(string username, string password)
    {
        var user = await userRepository.Load(username);
        if (user == null) return false;
        if (!passwordHasher.DoesPasswordMatch(user.Salt, user.Hash, password))     return false;
        var token = tokenGenerator.Encode(username, user.PlayerName);
        cookieHelper.SetCookie(CookieName, token);
        return true;
    }
}
</code></pre>

<h3>Arrange-Act-Assert</h3>

<p>The canonical unit test is one where you want to test a piece of code one single way and you want to verify that one effect of that code was correct. Depending on the complexity of the code, some setup might be necessary before the code under test can be executed. This pattern of setting up proper conditions for a test, running the code under test, and then verifying the result is often called the <em>arrange-act-assert</em> pattern.</p>

<p>Using our example code above, here is an arrange-act-assert unit test for the case when the username is valid but an incorrect password is supplied.</p>

<pre><code>public class WhenExecutingSignInWithIncorrectPassword :     WithAnAutomocked&lt;SignInCommand&gt;
{
    [Test]
    public void ItShouldFail()
    {
        GetMock&lt;IUserRepository&gt;().Setup(x =&gt; x.Load(IsAny&lt;string&gt;())).Returns    (Task.FromResult(new User()));
        GetMock&lt;IPasswordHasher&gt;().Setup(x =&gt; x.DoesPasswordMatch(IsAny&lt;string&gt;    (), IsAny&lt;string&gt;(), IsAny&lt;string&gt;())).Returns(false);

        var result = ClassUnderTest.Execute("username", "incorrect password").    Result;

        Assert.That(result, Is.False);
    }
}
</code></pre>

<p>The <code>WithAnAutomocked&lt;T&gt;</code> base class is just a helper class that instantiates the class provided (the <code>SignInCommand</code> class in the code above) and injects all of the constructor dependencies for that class as Moq mocks. It uses <a href="https://github.com/darrencauthon/AutoMoq">AutoMoq</a> to do this.</p>

<p>With this example test you can see a strong arrange-act-assert pattern. There is code to set up some behavior on some mocks that the code under test depends on (arrange). The code under test is then executed (act), and finally we check to make sure the code did what is was supposed to (assert).</p>

<p>This type of test is great when you want to test for a specific situation or a specific set of inputs. It is also great when you want to verify a single thing about the execution of your code.</p>

<h3>One Act, Many Assertions</h3>

<p>Sometimes when testing a piece of code, we want to execute the code and then make assertions about multiple effects that code had. Again, we could create a standard arrange-act-assert style test to handle this case. We would just need to add multiple assertions to the end of our test. Some people are vehemently opposed to having multiple assertions in their tests. I’m not entirely opposed to it, but I do consider it a smell. One of the problems with multiple assertions is that when a test fails it can become difficult to determine what part of the code has actually failed. If the assertions are independent, but they all pass or fail together it can be necessary to resort to stack traces or error messages to determine what part of the code has actually failed. Also, in the case of Nunit at least, the failure of a single assertion in a test will cause the execution of the test to halt. So a failure early on in a test can mask additional failures later in the test.</p>

<p>Fortunately, there is a solution to this problem. The solution is to use a style sometimes referred to as behavior driven development (BDD) testing or <em>specification testing</em>.</p>

<pre><code>public class WhenExecutingValidSignIn : WithAnAutomocked&lt;SignInCommand&gt;
{
    private bool result;
    private string tokenValue = "token value";

    [SetUp]
    public void SetUp()
    {
        var user = new User { Username = "username", PlayerName = "Player     Name" };
        GetMock&lt;IUserRepository&gt;().Setup(x =&gt; x.Load("username")).Returns(Task.    FromResult(user));
        GetMock&lt;ITokenGenerator&gt;().Setup(x =&gt; x.Encode("username", "Player     Name")).Returns(tokenValue);
        GetMock&lt;IPasswordHasher&gt;().Setup(x =&gt; x.DoesPasswordMatch(IsAny&lt;string&gt;    (), IsAny&lt;string&gt;(), IsAny&lt;string&gt;())).Returns(true);
        result = ClassUnderTest.Execute("username", "password").Result;
    }

    [Test]
    public void ShouldSucceed() =&gt; Assert.That(result, Is.True);

    [Test]
    public void ShouldSetCookie() =&gt; GetMock&lt;ICookieHelper&gt;().Verify(x =&gt; x.    SetCookie(SignInCommand.CookieName, tokenValue));
}
</code></pre>

<p>In this example we go back to the <code>SignInCommand</code> example. But in this case we are testing the path where sign in was successful. With this particular code we want to make sure that the correct result is returned and that the cookie was set. These two results could easily succeed or fail independently from each other. So putting them as two assertions in the same test doesn’t make sense for the reasons mentioned above.</p>

<p>This type of test is great when there are multiple effects a piece of code can have that can all succeed or fail independently. In this particular example there are only two such assertions, but you can imagine more complex pieces of code could have many more. This particular example just uses Nunit to get this style of test, but there are also testing frameworks geared specifically for this type of test. Some examples in .NET include <a href="https://github.com/machine/machine.specifications">Machine.Specifications</a> and <a href="https://github.com/derekgreer/nunit.specifications">Nunit.Specifications</a>.</p>

<h3>Test Cases</h3>

<p>Sometimes we have code where we want to test a lot of different inputs matched with a lot of different outputs. Since our previous example code for the <code>SignInCommand</code> doesn’t lend itself terribly well to this type of test, let’s use a different example for this type of unit test. Imagine we wanted to test some code that takes an integer and returns that integer value converted to a <a href="https://github.com/theparticleman/RomanNumeralKataSolution">Roman numeral</a>. For this type of algorithmic code we’ll want to provide lots of different inputs to test all the different Roman numeral conversions and verify that we get the correct output back. We could write a new arrange-act-assert style test for each input and output set we want to test. But if we did that we’d end up with a lot of duplicate code. And you should make sure your test code is maintainable as possible, just like with your production code.</p>

<p>Fortunately, it’s possible to write unit tests for these types of scenarios as well. Nunit has a feature specifically for this type of test. If your unit testing library of choice doesn’t have such a feature you can always create some type of collection to store your input-output pairs and then iterate over that collection. It’s not quite as slick as when the capability is built in to your unit testing library, but it can still remove duplicate code and allow you to add new test cases quickly.</p>

<pre><code>public class RomanNumeralConversionTests
{
    [TestCase(0, "")]
    [TestCase(1, "I")]
    [TestCase(2, "II")]
    [TestCase(4, "IV")]
    [TestCase(5, "V")]
    [TestCase(6, "VI")]
    [TestCase(10, "X")]
    [TestCase(9, "IX")]
    [TestCase(40, "XL")]
    [TestCase(50, "L")]
    [TestCase(90, "XC")]
    [TestCase(100, "C")]
    [TestCase(400, "CD")]
    [TestCase(500, "D")]
    [TestCase(900, "CM")]
    [TestCase(1000, "M")]
    public void ConvertTests(int arabic, string roman)
    {
        Assert.That(ArabicToRoman.Convert(arabic), Is.EqualTo(roman));
    }
}
</code></pre>

<p>In this example you can see that if we had different arrange-act-assert style tests for every input and output combination there would be a lot of duplicate code. And every time we wanted to add an additional test case, it would involve duplicating more code. Using the <code>TestCase</code> attribute from Nunit, we can remove a lot of duplication and make it easy to add test cases in the future. We also are able to more clearly indicate what it is we are trying to test. We’re not trying to test that <code>1</code> converts to <code>I</code> necessarily. We’re really trying to test that the entire conversion process works as expected. Putting all of our conversion related tests together using <em>test cases</em> like this allows us to better show our intent.</p>

<h3>Which Type of Unit Test Should You Use?</h3>

<p>The three types of unit tests described above are each great in their own context. If you’re testing code that has multiple effects that can succeed or fail independently, a <em>specification test</em> might be a great option. If you’re testing code where you want to make sure that multiple sets of input and output are correct, a <em>test case</em> style test might be a great option. And when in doubt, a standard <em>arrange-act-assert test</em> is a great place to start.</p>

<p>Remember that test code is code too. It should be crafted with care, just like production code. It should have duplication removed, should be refactored to increase maintainability, and should evolve over time. Hopefully the examples given here will give you some ideas to help your test code be even better than it already is.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Practice Matters</title>
      <link>https://mythicant.com/blog/practice-matters</link>
      <description />
      <pubDate>Fri, 09 Nov 2018 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/practice-matters/">Pluralsight Tech Blog</a></em></p>

<h3>Origami</h3>

<p>I recently gave a presentation titled “What I Learned About Software Development from Origami”. Originally it was just going to be a fun way to combine two seemingly unrelated interests of mine. But I ended up getting a valuable learning out of it.</p>

<p>I shared a lot of pictures of origami, but the image below ended up being key to the presentation.</p>

<p><img src="/images/practice-matters-origami-boxes.jpg" alt="Origami Boxes" /></p>

<p>You’ll notice this picture has two origami boxes. The one on the right has pretty straight folds and looks pretty square. The one on left has folds that look less straight and less square. It’s still a box, but the one on the right definitely looks more box-like.</p>

<p>So what’s the difference between these two origami boxes? They were both made with the same size and type of paper. Both were made using the same set of instructions. The difference between the two boxes is not in what folds were made but rather how those folds were made.</p>

<p>But how the folds in origami are made can have more impact than just how the resulting origami model looks. Let’s look at another image.</p>

<p><img src="/images/practice-matters-origami-cup-and-yoda.jpg" alt="Origami Cup and Yoda" /></p>

<p>In the case of the origami cup (a relatively simple origami model), if the folds are not exactly straight and perfectly crisp then the cup will probably turn out fine anyway. However, in the case of the origami Yoda (a much more complicated origami model), if the folds are not pretty close to exact then everyone’s favorite short, green force wielder could look misshapen and unrecognizable. If the folds are far enough off from ideal, you might not even be able to complete the model at all. In this case the quality of the folds could determine not just how good the origami model looks at the end, but what origami models are even possible.</p>

<h3>Isn’t This Post About Practice?</h3>

<p>So what does all of this have to do with practice? From the origami examples above we can anecdotally conclude that the quality of folds can determine both the quality of the origami model as well as what origami models are possible. So how does one learn to make better folds? Practice of course!</p>

<p>Another one of the images I shared was an example of what happens when your folds aren’t of high quality. When I was folding the model to take a picture of it, it was actually one of the most challenging models I made for the entire presentation. Why? Because I don’t practice doing origami folds poorly. I only practice doing them well. So doing the folds poorly was a challenge.</p>

<h3>What About Software Development?</h3>

<p>This is a technical blog about software development, and so far in this post all I’ve talked about is origami. How does all of this relate to software development? In my presentation I compared origami to software development. In origami what folds are made is important, but so is <em>how</em> those folds are made. In software development what software we make is important, but so is <em>how</em> we make it.</p>

<p>What do I mean when I say “how we make software”? I mean things like:</p>

<ul>
<li>Do we write automated tests for our software?</li>
<li>Do we write those tests using test driven development?</li>
<li>Do we strive to write our software in a way that is easy to read and maintain in the future?</li>
<li>Do we integrate the changes we make to our software with the changes other people make to that software frequently (ideally at least daily)?</li>
<li>Do we deploy our changes to our customers frequently?</li>
<li>Do we collaborate with others when we write our software?</li>
</ul>

<p>The exact list of what practices define the “how” in how we write software is certainly up for debate. But I would argue that like with origami, the “how” not only impacts the quality of the end result, but also impacts what end results we can achieve.</p>

<h3>Back to Practice</h3>

<p>In origami, a couple of great ways to practice and improve are to fold the same models lots of times, and to learn to make new models you haven’t made before. Are there ways that we can practice the “how” of software development like we can practice the “how” of origami? Sure there are!</p>

<p>The Global Day of Coderetreat is coming up soon. If you’re not familiar with the idea of a coderetreat, this description from <a href="https://www.coderetreat.org/pages/about/">coderetreat.org</a> may help.</p>

<blockquote>
  <p>Coderetreat is a day-long, intensive practice event, focusing on the fundamentals of software development and design. By providing developers the opportunity to take part in focused practice, away from the pressures of ‘getting things done’, the coderetreat format has proven itself to be a highly effective means of skill improvement. Practicing the basic principles of modular and object-oriented design, developers can improve their ability to write code that minimizes the cost of change over time.</p>
</blockquote>

<p>You may have noticed the word “practice” or “practicing” occurs in every sentence in that description. That seems to suggest that the idea of practice is important in a coderetreat. What kinds of things do people practice during Global Day of Coderetreat? They practice things like TDD, pairing and writing clean code. The goal of Global Day of Coderetreat is specifically to practice the “how” of software development.</p>

<p>I would strongly encourage you to participate in a Global Day of Coderetreat, especially if you haven’t before. But maybe coderetreats aren’t your thing. That’s okay. There are other ways to practice too. I like to use code katas to practice things like TDD and clean code. Using a code kata you’re already familiar with can also be a great way to practice learning a new programming language or learning more about a feature in your current programming language. I like to use small side projects to practice things like automated build pipelines and deployments. It’s okay if you don’t practice the same way I do. But find ways to practice. Find time to deliberately practice. And like with origami, be willing to learn new things so you can learn new ways to practice.</p>

<p>Master Yoda was right. Wars do not make one great. But practice might.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Living In A World Without QA</title>
      <link>https://mythicant.com/blog/living-in-a-world-without-qa</link>
      <description />
      <pubDate>Fri, 13 Jul 2018 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/living-in-a-world-without-qa/">Pluralsight Tech Blog</a></em></p>

<p>At Pluralsight our development teams do not have dedicated QA people. We also don’t have a dedicated QA team that is separate from the development team. Why do we do that? How does it work?</p>

<h3>Does No QA Mean No Testing?</h3>

<p>Quite the contrary! Not having dedicated QA people means that testing is the responsibility of the whole team, not just a few members of the team or a completely separate team. It forces everyone on the team to think about how to ensure the quality of the code produced.</p>

<p>Teams are also encouraged to automate as much of their testing as possible, following the <a href="https://martinfowler.com/bliki/TestPyramid.html">test pyramid model</a>. <a href="https://martinfowler.com/bliki/TestDrivenDevelopment.html">Test driven development</a> is a great way to develop these automated tests. Teams will typically have large suites of automated tests at lots of <a href="https://www.pluralsight.com/tech-blog/what-kind-of-test">different levels</a> that run every time code is changed or deployed. Teams will also sometimes manually test new features locally or in our staging environment (and sometimes in our production environment as well when the feature is behind a feature toggle), but the majority of testing occurs in an automated fashion.</p>

<h3>Why Not Have QA?</h3>

<p>The lack of dedicated QA people on a team can be mitigated by making testing the responsibility of the whole team and by having comprehensive suites of automated tests. But wouldn’t it be better if we did those things and had dedicated QA people too? Well, it turns out that having separate QA people can introduce some significant problems with a team’s ability to deliver software quickly and frequently.</p>

<p>At Pluralsight we practice <a href="https://en.wikipedia.org/wiki/Lean_software_development">lean software development</a>. One of the principles of lean is to reduce waste. One type of waste that can occur is unfinished work accumulating in queues. Having separate QA people doesn’t guarantee there will be a queue with unfinished work from developers, but it is something that can easily happen. Many of the developers at Pluralsight have experienced this in practice at other places of employment. So rather than attempt to manage that queue of work and reduce the amount of waste it can generate, we choose to <a href="https://www.pluralsight.com/tech-blog/avoiding-secondary-work">remove it completely</a>.</p>

<h3>Does This Actually Work?</h3>

<p>So far it has worked surprisingly well. We never have development teams waiting on QA in order to deploy a new feature. We do sometimes have bugs that we have to fix, but we have a small enough number of those that we do them as part of our normal workflow. We don’t use a separate bug tracking database to keep track of them. In 2017 we deployed a little over 4200 times to production across all our teams. Of all those deploys, approximately 3% were rollbacks. We don’t keep statistics on the reason why various deploys were rolled back, so it’s hard to know which of those rollbacks were because of bugs or other adverse customer impact. In some situations this level of rollbacks might not be acceptable, but in our situation it is.</p>

<h3>Conclusion</h3>

<p>So how does not having dedicated QA people feel in practice? To me as a developer it actually feels really good. It means that for stuff I’m working on I don’t have to hand it off to another person or group and wait for them to process it. I feel responsibility for not just ensuring that I write quality code, but having a way to prove that my code does what I think it should. It means I can deploy things to production much faster and more frequently, which means I can get feedback from actual customers faster and more frequently.</p>

<p>That said, working without dedicated QA people does take some different skills than working with them. And just like any other skill, the skill of working without dedicated QA people can take time to acquire and improve.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Shu Ha Ri</title>
      <link>https://mythicant.com/blog/shu-ha-ri</link>
      <description />
      <pubDate>Fri, 01 Jun 2018 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/shu-ha-ri/">Pluralsight Tech Blog</a></em></p>

<p>There are various ways to think about people gaining and improving skills. One such way is called Shu Ha Ri. It comes from martial arts, but the underlying idea can be applied to other domains as well. Many other much smarter people than I (such as <a href="https://martinfowler.com/bliki/ShuHaRi.html">Martin Fowler</a> and <a href="http://alistair.cockburn.us/Shu+Ha+Ri">Alistair Cockburn</a>) have already given their take on Shu Ha Ri. I would encourage you to read their words as well. In this blog post I’ll give my own interpretation of Shu Ha Ri as well as some observations I’ve had about it.</p>

<h3>Introduction</h3>

<p>So what is Shu Ha Ri? It is a way to describe skill acquisition using three levels, named <em>shu</em>, <em>ha</em>, and <em>ri</em>. There are different ways to describe these three levels. I like to describe them like this:</p>

<ul>
<li><em>Shu</em> - <em>Follow the rule.</em> At this stage learners are focused on what the rules of the skill are. Learners at this level often want a list of rules about what they should do and how they should do it. A lack of rules or excessive exceptions to the rules will cause confusion and frustration.</li>
<li><em>Ha</em> - <em>Bend the rule.</em> At this stage the learner has learned the basic rules of the skill and is now learning what the exceptions to the rules are. This stage can also start to include context specific rules. e.g. Rule X applies in situation Y but not in situation Z.</li>
<li><em>Ri</em> - <em>Be the rule.</em> At this stage the specific rules are less important than the principles behind the rules. In fact, the specific rules originally learned may now seem overly burdensome.</li>
</ul>

<h3>An Agile Example</h3>

<p>While the idea of Shu Ha Ri can be used in lots of contexts, it is often used in the context of various practices from agile software development. For this example I want to use an idealized adoption of the Scrum software development methodology.</p>

<p>When a team or organization first starts investigating agile methodologies they are often coming from a completely different methodology. Therefore any agile methodology will be foreign to them. They want to know exactly what they should do to “be agile.” Scrum has a lot of specific practices around specific ceremonies, such as a daily standup meetings, sprint planning meetings, or retrospectives. This looks a lot like a list of rules to a new learner. Newcomers to Scrum will tend to worry about things like exactly how many weeks their sprint should be, what exactly people should and shouldn’t say during the daily standup, or what questions should be discussed during a retrospective. The rules are completely foreign so they want to know exactly what those rules are. This is the essence of <em>shu</em>: learn the rules.</p>

<p>One of the beauties of Scrum (and most other agile and lean methodologies) is that it won’t necessarily solve your problems, but it will make them painfully obvious to you. As learners become more familiar with the rules around specific meetings and practices, they will start to run into problems. They may notice that daily stand up meetings tend to be boring. Constantly having work spill over from one sprint to the next may cause them problems. They may discover other pain points. Some of these pain points may suggest areas where they should modify their behavior to fit the methodology, but others may suggest areas where they should modify the methodology to fit their unique needs. This is the essence of <em>ha</em>: learn when to modify the rules and adjust them in different contexts.</p>

<p>Assuming that the team or organization continues to improve their development practices using retrospectives and other feedback mechanisms they will likely reach a point where they feel frustration despite following all the Scrum practices. Scrum has a lot of specific practices around sprints and the related meetings, but it says very little about technical practices. Realizing that the specific rules of Scrum might be insufficient for their context could be a source of frustration for learners. The team might have moved to pair programming or <a href="https://www.pluralsight.com/tech-blog/mob-programming">mob programming</a>, reducing the need for a daily standup meeting. The team may have developed sufficient discipline and automation that they can release whenever they want, not just at the end of a sprint. Suddenly they start feeling constrained by the rules of Scrum. Rather than helping, the rules are hindering the performance of the team. This is the essence of ri: the underlying principles behind the rules have been learned and the specifics of the rules are no longer important.</p>

<h3>Some Observations</h3>

<p>I’d like to share a few observations I’ve had about Shu Ha Ri and how it can be applied to some common situations.</p>

<h4>Different people, different skills, different levels</h4>

<p>The first observation is pretty straight forward. It is that there are different skill levels. Different people have different levels of skill. And different people are at different levels in different skills. For example, I might be at a <em>ri</em> level at test driven development while you are at a <em>shu</em> level. But at the same time you might be at a <em>ri</em> level at database design while I am at a <em>shu</em> level in that same skill. There might be other skills at which I am at a <em>ha</em> level. Most importantly, just because a person is at a given level in a given skill it does not mean they are that level of person! Just because I am at a <em>shu</em> level in a particular skill it doesn’t mean I’m a <em>shu</em> person. Nor does it mean that I can’t improve in that or any other skill.</p>

<h4>Expert beginner</h4>

<p>There is an interesting point when learners are approaching the end of the <em>shu</em> phase or entering the <em>ha</em> phase for a given skill. <em>Shu</em> and <em>ha</em> are all about learning the rules and finding exceptions to the rule. It can be easy for learners to conflate mastering the rules of a skill with mastering the skill itself. This pitfall is so common that it even has a special name: expert beginner. The expert beginner trap is an important one for any learner to keep in mind as they are acquiring a new skill. It’s always worth asking a self-reflective question about whether you have truly mastered a skill or if you have only mastered the beginning rules of that skill.</p>

<h4>Different perspectives</h4>

<p>Differences in perspective can be challenging in all kinds of contexts. Shu Ha Ri is no different. The most extreme case is between <em>shu</em> learners and <em>ri</em> learners.</p>

<p>A <em>shu</em> learner looking at a <em>ri</em> learner will see someone who doesn’t follow any of the rules. The <em>ri</em> learner often won’t be able to explain why they do what they do in a way that makes sense to a <em>shu</em> learner, instead giving reasons like “That’s just the way you should do it” or “It just feels right”. To a <em>shu</em> learner a <em>ri</em> learner may do things that don’t make sense or that look like chaos and anarchy.</p>

<p>On the other hand, a <em>ri</em> learner looking at a <em>shu</em> learner will see someone longing for constraints, for lists of things they should and shouldn’t do, for explanations of every step of every process. The way a <em>shu</em> learner wants to work will often feel byzantine and cumbersome to a <em>ri</em> learner.</p>

<p>Because of these different perspectives it can be challenging for a <em>shu</em> learner and a <em>ri</em> learner to relate to each other. It can be hard for the <em>ri</em> learner to remember what it was like to be the <em>shu</em> learner. And it can be hard for the <em>shu</em> learner to imagine the things the <em>ri</em> learner is talking about. Sometimes a <em>ha</em> learner can help bridge the gap between a <em>shu</em> learner and a <em>ri</em> learner.</p>

<h3>Conclusion</h3>

<p>As you are working to acquire new skills, think about how you will need to progress through that learning. Keep in mind that you’ll probably need to learn a lot of rules before you can start bending them.</p>

<p>Next time you’re having a debate with someone on a given topic, stop and think about what level each of you are at on that topic. Are you both at the same level? Are you at different levels? Is one of you at <em>shu</em> while the other is at <em>ri</em>? Are either of you falling prey to the expert beginner trap?</p>

<p>If you’re a <em>shu</em> learner in a given skill, try to accept the advice a <em>ri</em> learner provides, even if it sounds crazy. If you’re a <em>ri</em> learner, try to remember what it was like to be the <em>shu</em> learner and help them through that part of their journey as best you can. And if you’re a <em>ha</em> learner, try to keep the <em>shu</em> learners and <em>ri</em> learners around you from killing each other.</p>
]]></content:encoded>
    </item>
    <item>
      <title>What Does Deployment Look Like at Pluralsight?</title>
      <link>https://mythicant.com/blog/what-does-deployment-look-like-at-pluralsight</link>
      <description />
      <pubDate>Mon, 19 Dec 2016 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><em>This blog post was originally posted on the <a href="https://www.pluralsight.com/tech-blog/what-does-deployment-look-like-at-pluralsight/">Pluralsight Tech Blog</a></em></p>

<p>It’s hard for code to provide value unless it’s accessible by users. If our code doesn’t provide value, why are we writing it? The way we get code into our production environments at Pluralsight has changed over time and varies somewhat from team to team, but getting code where users can get value from it is something that’s important to us at Pluralsight.</p>

<p>So how does code get from a development machine to a production machine at Pluralsight?</p>

<h3>During Development</h3>

<p>The process starts when the code is being written. We have a rule that all production code should have at least two sets of eyes on it before it goes out. That usually takes the form of pair programming, but sometimes happens via code reviews or mob programming. That choice is made by individual teams. We usually test drive our code, so most of our code has a fair number of tests we can run. We generally run all of our unit tests (not just the ones for the code we’re currently working on) before we push the code to our central repository in Github. Sometimes we’ll write and run other types of automated tests as well, but we can talk about that more later.</p>

<h3>Integrate Early, Integrate Often</h3>

<p>When we actually push the code, where does it go? It goes in our master branch of course. Master should always be deployable. If your code shouldn’t be deployed to production, you shouldn’t push it yet. That doesn’t mean you should go for a long time between pushing your code. It means you should write your code in smaller chunks. The reason we don’t use branches is because they tend to be long lived. If you have code in multiple, long lived branches then the code in those branches is not getting integrated. I don’t know if the code in my branch will work with the code in your branch until they are actually merged in to the same place. The sooner that happens the sooner we know if there are going to be problems. We do occasionally use short lived branches but tend to favor feature toggles over branches.</p>

<p>At Pluralsight we use TeamCity as our continuous integration server. When code is pushed to a Git repository, a build is automatically kicked off for that code. A build consists of compilation (or transpilation if necessary) and executing all unit tests. If either of those steps fail the build fails and the code doesn’t go any further. For some code bases we have additional types of automated tests, not just unit tests. For us, these usually take the form of what we call integration tests (tests for code that relies on a third party service like a database or external web service) or acceptance tests (tests for multiple code units from a business perspective, but below the UI layer and not running in a full environment). Most of these types of tests would run at this point if the primary compile+unit tests build succeeds. If these additional tests fail, the build fails and the code doesn’t go any further.</p>

<h3>Deploying to Stage</h3>

<p>If the code compiles and all the tests pass, then the code is automatically deployed to our staging environment. There is a separate Team City build that triggers when the previous builds succeed that initiates the deploy. For our .NET projects (and a few of our Node projects) we use Octopus Deploy. Before Octopus Deploy was available we had a custom built tool that was similar but not nearly as feature rich. Octopus doesn’t have every possible feature that we could dream of and it occasionally gets confused, but 99% of the time it just works and it’s great. For our projects that don’t use Octopus Deploy, we have a separate Team City build for that project that uses SaltStack to push the code to the desired machines.</p>

<p>Once the code gets deployed to our staging environment we can do any manual testing we think we need to. This effort is usually pretty minimal, but sometimes there are things that are impossible, extremely difficult or very time consuming to test automatically or outside of a fully functional environment. In addition to any manual testing we want to do, we also have a set of UI tests that start running automatically on every new deploy to staging. UI tests are notoriously slow and brittle, so we try not to have too many of them. We only want to test the stuff that absolutely MUST work. For example, we have tests to make sure that new users can sign up and that existing users can watch videos. If those things don’t work our site isn’t very useful. If these UI tests fail then that build won’t be going to production.</p>

<h3>On to Production</h3>

<p>If all of our automatic tests (and whatever manually tests we deem necessary) look good, we then have the option to deploy our code to production. This is a decision made by the team who worked on the code. That means developers in conjunction with people from product management. The team might also coordinate with other teams or other stakeholders if they need to. We try to make it so that decisions can stay inside the team as much as possible though. When we do deploy to production, we use the same process (Octopus Deploy or TeamCity + SaltStack) we used when we deployed to stage. This is a push button operation that causes the same binary files that are already in stage to be pushed to production machines, just with different configuration. In the case of code that is customer facing, we do this in a rolling fashion. For example, to update code on a web farm, we will take a set of web servers out of the load balancer pool, wait for active connections to drain off, update the code, potentially run some warm up scripts, and then put the web servers back in the load balancer pool. We don’t update all the web servers at once, so there is no down time for our users.</p>

<h3>Did We Break Anything?</h3>

<p>When we’re doing frequent deploys (and all the time really) we want to know if there are problems in production. We have a great support group who is super responsive about addressing customer issues and letting us know when they see problems. But making them our first line of defense when things go wrong isn’t fair to them. And it isn’t an ideal experience for our users. So we use a combination of automated tools to help us find problems before our customers find them and report them to our support group. For general monitoring of server health we use New Relic. New Relic also gives us a few extras like response times and the like. We do have some custom metrics in New Relic as well that we’ve built ourselves to monitor specific things that are important to us. In addition to New Relic we aggregate our logs using ELK (Elasticsearch, Logstash, Kibana). If we notice a problem we can get access to all our production logs there to get more information about what’s going wrong. We can also set up alerting on logs (e.g. raise an alert if a certain number of errors get logged within a given time period).</p>

<p>So with all our testing and monitoring nothing every goes wrong, right? Well, things usually don’t go wrong. According to out internal metrics, in September 2016 we deployed to production 418 times. That is across all teams and all deployable units. Of those 418 deploys, 10 of them were to an older version than was already in production. That’s a rollback rate of about 2%. We very seldom have critical issues that we do rollbacks for. Most of them are for small issues. e.g. Incorrect text on a page, performance regressions, etc. With Octopus Deploy (and the custom tool we used prior to Octopus Deploy), a rollback is a single button click away. So far our business has found our frequency, severity and difficulty of rollbacks to be acceptable.</p>

<h3>Conclusion</h3>

<p>Deploying frequently is not only possible, it’s actually an advantage. It allows us to get feedback from actual users sooner. It allows us to release without fear because what has changed since the last release is usually so small. It allows us to respond to changing business situations more quickly. And personally, it makes me happier.</p>
]]></content:encoded>
    </item>
    <item>
      <title>SONR Trailer</title>
      <link>https://mythicant.com/blog/sonr-trailer</link>
      <description />
      <pubDate>Sun, 18 Jul 2010 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><div style="padding:75% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/13443384?badge=0&amp;autopause=0&amp;player_id=0&amp;app_id=58479&amp;h=b680ce21e1" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%;" title="SONR Trailer"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script></p>

<p>SONR was originally started as an entry in the <a href="https://forums.tigsource.com/index.php?board=38.0">TIGSource Assemblee competition</a>.  Unfortunately, I didn’t really get far enough to submit anything for the competition, but I liked the game, so I’ve kept working on it. </p>

<p>I decided a while ago I should make a trailer for SONR before actually finishing the game.  I’m not sure exactly why I decided that would be a good idea.  Maybe because I knew it would be a while before the whole game got done?  I’ve never made an actual trailer for a game before.  Gameplay videos yes, trailers no.  I’d appreciate any feedback on it that anyone has.  Cool?  Lame?  Confusing?  Waste of time?  I was hoping it would convey some of the emotions that I hope the final game will contain. </p>

<p>Speaking of my hopes for the final game, I thought I’d make a list of my reasons for making/goals behind SONR.  Because, you know, the <code>&lt;ul&gt;</code> tag doesn’t get enough lovin’ in this world.</p>

<ul>
<li><p>I guess the first reason I should mention for making SONR is to participate in a TIGSource competition.  If you haven’t done it before and have any inclination to do so I would highly recommend it.  You don’t have to be a coder.  You can do art, music, level design or even just play testing.  People often team up to work on entries.</p></li>
<li><p>One of the requirements for the competition was that you had to use assets provided in the first part of the competition and you couldn’t modify them outside of code.  I thought it sounded like fun to do all the graphics manipulations and enhancements in code.  And it kind of was.  One of my goals with SONR is to make it look cool.  And I think so far it’s turned out looking pretty good.  Not perfect, but pretty good.  But I think going forward I might relax some of the requirements from the competition.</p></li>
<li><p>I feel like my games so far have lacked something.  Depth?  Emotion?  Something like that.  I want this one to have more emotion.  I decided to use something Edmund McMillen said about making <a href="https://en.wikipedia.org/wiki/Aether_(video_game)">Aether</a> and use some experiences from my own life.  Or at least some emotions I’ve felt strongly at one point or another in my life.  We’ll see how that goes.</p></li>
<li><p>As mentioned previously, Ninja Robot Winning Gameshow ended up being much harder than I meant it to be.  I wanted it to be more fun than hard.  With SONR I’m going to try again for more fun than hard.  I’m hoping the visuals + emotion + exploration + easier movement and good combat + reasonable AI + having buddies to help you out = fun gameplay.  And I’m going to let more people test it than I did with NRWG.</p></li>
<li><p>And finally, I wanted some of the stuff that I built for SONR to translate over into framework items that I could use in other, future games.  I’m hoping after coding some more games I’ll have a pretty good idea of what things I’ll want to reuse and which things I don’t.</p></li>
<li><p>I guess another way to sum most of that up is, I want SONR to have, as ⦁  Kurt puts it, “soul”.</p></li>
</ul>

<p>So those are some of my goals.  After I actually get done I’ll plan to do a bit of a retrospective as I have for some other games and see how well I did.  In the meantime, there are a few things I’ve already learned and some changes I’m going to make going forward.</p>

<ul>
<li><p>Doing pixel-level collision detection really isn’t nearly as fun as it sounds, if you can imagine that!</p></li>
<li><p>As mentioned above, doing all the effects and image manipulation in code is an interesting exercise, but in the end not terribly interesting.  I’d rather let someone who enjoys doing that write some tool for me (like the excellent <a href="https://www.getpaint.net/">Paint.NET</a>) and just use that.  Much faster that way.</p></li>
<li><p>Having a two year old son does terrible things to one’s supply of available game playing time, and even worse things to one’s supply of available game making time.  Though I was quite pleased that one of his new favorite videos to watch is actually this SONR trailer.  It gives me high hopes for his future video game playing and general geekiness levels.</p></li>
<li><p>Sadly, after creating all the collision detection, image scaling and rotation and game loop code by hand, I think I’m going to basically scrap it all going forward and use a third party game framework.  At the moment I’m leaning towards <a href="https://flatredball.com/">Flat Red Ball</a>.  It’s kind of a hard decision for me to make.  No one likes to throw away perfectly good code.  And while my code does work, it has some limitations that I’m not terribly interested in building solutions to.  I’ve decided I would like hardware acceleration, better camera support, better image rotation and collision detection, better framerate control among other things.  A lot of that comes for free with a game framework and doesn’t come for free if I have to code it.  I’d rather spend time making my game than writing multi-threaded frame rendering code.  Plus I think a good amount of my code will be reusable.  Most of the game logic and characters and stuff should be able to translate over fairly well I think.  So I’m going to try it and see what happens.  If I crash and burn terribly, I’ll be sure to let you know.</p></li>
<li><p>My combat system still sucks.  It’s better than it was originally, but still needs some work.  Having buddies follow you around and help you makes it funner, but it’s still not where I want it to be.  Once I transition to a new framework, combat is going to be my biggest area of focus.</p></li>
<li><p>So far I’ve only implemented keyboard support.  I think using a gamepad will probably make the game funner.  I want to avoid requiring a gamepad though, since I know not everyone has one.</p></li>
</ul>

<p>Well, that’s probably enough talking (or rather writing) for now.  SONR still needs lots of code and it’s not going to write itself.  So let me know what you think of the trailer and the current look of SONR, and I’ll go write some awesome code. </p>

<p>P.S. All the footage in the video is current in-game video.  The video looks okay, but the actual game looks way better.  The video has a bunch of compression artifacts which the actual game does not (especially noticeable at larger sizes).  I need to get some better video editting tools than what I currently have.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>