<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pascal Dennerly</title>
    <description>The latest articles on DEV Community by Pascal Dennerly (@dnnrly).</description>
    <link>https://dev.to/dnnrly</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F339179%2F7715bf92-b938-4c5a-b03e-f5658ad73c62.jpg</url>
      <title>DEV Community: Pascal Dennerly</title>
      <link>https://dev.to/dnnrly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dnnrly"/>
    <language>en</language>
    <item>
      <title>GSL: Because Your Architecture Diagrams Should Be Searchable</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Tue, 07 Jul 2026 16:43:55 +0000</pubDate>
      <link>https://dev.to/dnnrly/gsl-because-your-architecture-diagrams-should-be-searchable-4lf0</link>
      <guid>https://dev.to/dnnrly/gsl-because-your-architecture-diagrams-should-be-searchable-4lf0</guid>
      <description>&lt;p&gt;We’ve all been there. You start documenting a system with a simple "Box and Arrow" diagram. At first, it’s clean. Then reality sets in.&lt;/p&gt;

&lt;p&gt;You need to show which components are in the public subnet versus the private one. You need to distinguish between synchronous REST calls and asynchronous events. You need to highlight which services are within the scope of a specific compliance audit.&lt;/p&gt;

&lt;p&gt;Before you know it, your &lt;strong&gt;PlantUML&lt;/strong&gt; or &lt;strong&gt;Mermaid&lt;/strong&gt; file is a 500-line wall of text. The biggest heartbreak? Nothing ages faster than a PDF of a system architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: The "Diagramming Tax"
&lt;/h2&gt;

&lt;p&gt;I’ve spent a lot of time in the trenches of software architecture documentation. Tools like PlantUML are fantastic for simple graphs, but they have a breaking point.&lt;/p&gt;

&lt;p&gt;The "niggles" start when you want to annotate a graph without affecting the layout, or when you need to represent a node that lives in multiple logical worlds. PlantUML doesn't really allow you to attach metadata to a component without the tool trying to "draw" that metadata.&lt;/p&gt;

&lt;p&gt;More importantly, these diagrams are &lt;strong&gt;write-only&lt;/strong&gt;. You can't ask a PlantUML file: &lt;em&gt;"Show me the blast radius if this internal service is compromised."&lt;/em&gt; You just have to squint at the spaghetti and hope your brain can parse the connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter GSL: Architecture as a Queryable Model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GSL (Graph Selector Language)&lt;/strong&gt; is an experiment in treating architecture as data first, and an image second. It’s born from a simple desire: I wanted a format that was easy to version-control, easy to diff, and—most importantly—easy to explore.&lt;/p&gt;

&lt;p&gt;GSL splits the problem into two distinct parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Language:&lt;/strong&gt; A way to describe the graph and annotate nodes with "Sets" using a simple &lt;code&gt;@tag&lt;/code&gt; syntax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Query Language:&lt;/strong&gt; An orthogonal tool to filter that graph and extract specific subgraphs.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Modeling Reality with Sets
&lt;/h3&gt;

&lt;p&gt;In GSL, nodes aren't trapped in a rigid hierarchy. A component can belong to as many "Sets" as you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node web @public
node gateway
node userService @internal @auth
node database @internal @datastore

user -&amp;gt; web # Implicit node creation for speed
web -&amp;gt; gateway
gateway -&amp;gt; userService
userService -&amp;gt; database

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@internal&lt;/code&gt; tag isn't just a label; it’s a dimension. You aren't restricted by how the graph looks; you're describing what it &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Exploring the Noise
&lt;/h3&gt;

&lt;p&gt;The real "Aha!" moment didn't come from writing the parser; it came from looking at a massive, generated architectural graph and realizing I couldn't find what I was looking for.&lt;/p&gt;

&lt;p&gt;By using an orthogonal query language, you can strip away the noise. If you only want to see the "Internal" world and how it connects to the outside, you run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;subgraph node in internal traverse both all&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The result isn't just a list—&lt;strong&gt;the output is another GSL graph.&lt;/strong&gt; This composability is the core of the experiment. You can pipe, filter, and zoom in on specific architectural stories without ever touching a mouse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond Documentation: The "Gut Feel" for Refactoring
&lt;/h2&gt;

&lt;p&gt;While GSL is currently in its early stages (v0.4.x), the vision goes beyond just making better Mermaid charts.&lt;/p&gt;

&lt;p&gt;I have a strong gut feel that by representing architecture in a queryable format, we open the door to &lt;strong&gt;automated architectural insights&lt;/strong&gt;. Imagine being able to programmatically detect "architectural smells"—unintended transitive dependencies or security policy violations—before a single line of infrastructure is even deployed.&lt;/p&gt;

&lt;p&gt;It moves us away from "drawing pictures" and toward &lt;strong&gt;advanced refactoring for systems&lt;/strong&gt;, supported by tooling that actually understands the relationships we've defined.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Ongoing Experiment
&lt;/h2&gt;

&lt;p&gt;GSL is a labor of love implemented in Go. I chose Go not because it’s a requirement for the language, but because it allowed me to quickly build a robust first implementation. I've used tools like &lt;a href="https://github.com/alecthomas/participle" rel="noopener noreferrer"&gt;Participle&lt;/a&gt; for parsing while challenging the implementation through rigorous testing to ensure it matches the mental model I had in mind.&lt;/p&gt;

&lt;p&gt;It’s still an experiment, and the query language is evolving rapidly. But the goal remains the same: &lt;strong&gt;Your architecture diagrams should be as searchable as your code.&lt;/strong&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Explore the project:&lt;/strong&gt; If you're tired of static diagrams and want to see a different way of modeling systems, check out the repo at &lt;a href="https://github.com/dnnrly/gsl-lang" rel="noopener noreferrer"&gt;github.com/dnnrly/gsl-lang&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>architecture</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Quitting early for the win!</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Sat, 14 Dec 2024 01:01:16 +0000</pubDate>
      <link>https://dev.to/dnnrly/quitting-early-for-the-win-2mh1</link>
      <guid>https://dev.to/dnnrly/quitting-early-for-the-win-2mh1</guid>
      <description>&lt;p&gt;Super short summary: Exiting your program when you get an error can be a good idea. Using &lt;a href="https://github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;gobail&lt;/a&gt; will make your life easier.&lt;/p&gt;

&lt;p&gt;When you get an error in your Go code, you'll normally see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doing my thing: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll notice a few things in this example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have to check whether there is an error&lt;/li&gt;
&lt;li&gt;There is some text that will help diagnose the error&lt;/li&gt;
&lt;li&gt;And the error is wrapped, passed back with the text&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So what happens next? Well it all happens again. You check the error value, describe it, pass it back. And then it all starts again.&lt;/p&gt;

&lt;p&gt;Why do we do this? Why all this effort?&lt;/p&gt;

&lt;p&gt;Well it all depends on the software that you're writing. When you get an error, you have to make a decision. What happens to that error?&lt;/p&gt;

&lt;p&gt;If you're writing an HTTP API responding to a request then eventually you're going to get to some kind of HTTP handler and you'll turn that error into some response - perhaps a little 400 with a polite reminder format their requests properly or possibly a 500 and a worrying message about the health of your application. Alternatively, if you're writing some kind of CLI tool then you might decide that the error will eventually get passed all the way back to your &lt;code&gt;main&lt;/code&gt; function. For any kind of program, you might decide that enough is enough - the program should just end because you can't do anything else.&lt;/p&gt;

&lt;p&gt;Let's look at this last option. When is it appropriate to just &lt;code&gt;exit&lt;/code&gt; your program? Here's a few reasons that I can think of:&lt;/p&gt;

&lt;p&gt;a. There's nothing else to be done, the error is so bad that everything has to stop right now&lt;br&gt;
b. There are no consequences to terminating the program (no cleanup is required, no status to respond with)&lt;br&gt;
c. Stopping early is desirable, perhaps you have a monitor that restarts the process cleanly&lt;/p&gt;

&lt;p&gt;Whatever the reason, you need to consider how you're going to exit cleanly. Now the first thing you're likely to try is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doing my thing: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks pretty similar to our original error handling code but with a couple of important differences. The first is kind of obvious - there's a honking great &lt;em&gt;stop-right-g*****n-now&lt;/em&gt; statement there. Your program is not going to continue. The second point is perhaps more important. The code that is calling this sample doesn't have worry about handling any errors. There are no additional code paths that have to be tested - we can trust that that the calling code doesn't have an &lt;code&gt;if&lt;/code&gt; block to test because there's nothing returned that we have to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your exits
&lt;/h2&gt;

&lt;p&gt;So I was being, perhaps, a little enthusiastic when I suggested you should just trust that your exit code is just going to work. You should probably check that the reason that you new program has stopped is for the right reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 1 - just run your program
&lt;/h3&gt;

&lt;p&gt;This feels like it should be easy. Here's some things to consider - in the most easy case, you're just going to run your program and trigger an error condition. For example, get your CLI tool to open a file that doesn't exist. You can do this manually for a few simple cases. When the number of tests goes up, you'll probably need some kind of automation around it to help you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Quick side note - this is probably the subject of a whole other blog post but my current favourite way of testing CLI tools uses &lt;a href="https://github.com/cucumber/godog" rel="noopener noreferrer"&gt;godog&lt;/a&gt; to write tests. It can be a little complex but I've found it supremely powerful. Here are some good examples of how I've approached it with &lt;a href="https://github.com/dnnrly/layli" rel="noopener noreferrer"&gt;layli&lt;/a&gt; and &lt;a href="https://github.com/dnnrly/wait-for" rel="noopener noreferrer"&gt;wait-for&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This approach will get you very far but sometimes it can be difficult to create the conditions that will properly exercise all of the code paths that you want to be confident about.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 2 - mock out the exit
&lt;/h3&gt;

&lt;p&gt;OK so now we're going to be using some of the features of the Go language. We don't actually have to call &lt;code&gt;os.Exit&lt;/code&gt; - we can call something that looks like it. So look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ExitFunc&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;customExit&lt;/span&gt; &lt;span class="n"&gt;ExitFunc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exit&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;someOtherFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doing my thing: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;customExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So how are we going to take advantage of this for our testing? As the function has now been turned into a variable (&lt;code&gt;customExit&lt;/code&gt;) then we can replace the value with something else that we want to do. Like so...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;sameAsTheAboveCode&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestOMGItsAllGoneWrong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;oldExit&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;customExit&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Make sure we reset the exit so it can be used elsewhere&lt;/span&gt;
        &lt;span class="n"&gt;customExit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldExit&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;exitCalled&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;customExit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;exitCalled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Set up the mocks so that someOtherFunc returns an error&lt;/span&gt;

    &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// Assume that we're using the fantastic stretchr/testify library here&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;True&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exitCalled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exitCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a much more unit-test friendly approach. You can check that the exit code used is correct - and that you actually called the exit function.&lt;/p&gt;

&lt;p&gt;On the surface, this looks great but there is one big problem - if your test passes, then you program will continue and execute the rest of the function when you expected it to exit. It will continue even though the test setup means that the rest of the execution is not valid and cause problems for your tests, such as causing panics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing code to remove tests
&lt;/h2&gt;

&lt;p&gt;Well, this sounds a bit extreme!&lt;/p&gt;

&lt;p&gt;I feel like I should explain... Typically in "well managed" companies you need to make sure that every line of code has been proved to be working before if can be put in front of your customers. Using the above techniques you may not be able to generate the correct coverage metrics to attest that you're good. Even if it's trivial to reason about.&lt;br&gt;
All of the examples above have assumed that when we get an error then we have to check it to decide what to do (Exit with vengeance). Wouldn't it be great if we were able to exit without having to check that there was an error?&lt;/p&gt;

&lt;p&gt;Let's see what we can do.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;checkExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"doing my thing: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;customExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;checkExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someOtherFunc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at the above example. The functionality is the same but the implementation of &lt;code&gt;myFunc&lt;/code&gt; is much simpler now - there are no conditionals. We can check the implementation of the &lt;code&gt;checkExit&lt;/code&gt; function in it's own tests, meaning that whatever is new in myFunc() can be much more easily verified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing &lt;a href="https://github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;gobail&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A new libraray, &lt;a href="https://github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;gobail&lt;/a&gt; has been  created that allows you to e confident that if there is an error then it will be handled without having to add complexity to your own code. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;gobail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;someOtherFunc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"with message"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;gobail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yetAnotherFunc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"with message"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This library has been fully tested, with coverage metrics, to prove it. You can safely use it without having to worry that an error will be skipped. It will also handle functions with 2 return values, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;gobail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Return2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return2ValsAndError&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrExitMsg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"something went wrong: %v"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice as well that you an include the error that is causing all of your problems.&lt;/p&gt;

&lt;p&gt;It's also possible to panic instead of exiting, printing our a stack trace and other contextual information from the program when the panic is invoked. Take a look at the &lt;a href="https://pkg.go.dev/github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;docs&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Isolating dependencies
&lt;/h2&gt;

&lt;p&gt;As you write software with &lt;a href="https://github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;gobail&lt;/a&gt;, you will notice that you will mostly have to use it when talking to external libraries. This has the additional code that you typically need to write to handle all of the error cases can be wrapped in a call to &lt;code&gt;Return&lt;/code&gt; or &lt;code&gt;Return2&lt;/code&gt; and assume that we will exit when necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Sometimes it's desirable to exit your program instead of handling your errors in detail. The &lt;a href="https://github.com/dnnrly/gobail" rel="noopener noreferrer"&gt;gobail&lt;/a&gt; library has been created and validated so that you don't have to worry about the detail of proving this.&lt;/p&gt;

&lt;p&gt;If you find an improvement that could be made or just have a suggestion then raise a PR or an issue on the repo and the developers will get on it when they can!&lt;/p&gt;

</description>
      <category>go</category>
      <category>exit</category>
      <category>panic</category>
      <category>gobail</category>
    </item>
    <item>
      <title>Introducing Layli</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Fri, 24 Nov 2023 22:20:15 +0000</pubDate>
      <link>https://dev.to/dnnrly/introducing-layli-31mn</link>
      <guid>https://dev.to/dnnrly/introducing-layli-31mn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a story about how my simple little alternative to PlantUML came about. Please check out &lt;a href="https://github.com/dnnrly/layli"&gt;layli&lt;/a&gt; if you just want to see the end result.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've been an avid user of &lt;a href="https://plantuml.com"&gt;PlantUML&lt;/a&gt; for &lt;em&gt;years&lt;/em&gt;. I love the ability to define my diagrams as code. Sequence diagrams, component diagrams - just define what connects to what and you have a diagram that you can put in &lt;code&gt;git&lt;/code&gt; and render in to any image format you choose.&lt;/p&gt;

&lt;p&gt;But.&lt;/p&gt;

&lt;p&gt;BUT....&lt;/p&gt;

&lt;p&gt;...very quickly, you find that your component diagrams end up looking a bit messy. So you use &lt;code&gt;linetype ortho&lt;/code&gt; to get the straight lines with corners, rather than curves. Then you have to arrange the boxes around the page and you add hidden connections (&lt;code&gt;-[hidden]-&amp;gt;&lt;/code&gt; and play with the line lengths (using &lt;code&gt;--&amp;gt;&lt;/code&gt; and &lt;code&gt;---&amp;gt;&lt;/code&gt;, perhaps even &lt;code&gt;----&amp;gt;&lt;/code&gt;). All of a sudden you discover that your simple diagram becomes a mess of crossing lines and kludges to separate the nodes so that it looks pretty.&lt;/p&gt;

&lt;p&gt;So what to do? I love the ability to specify my diagrams as code. This works really nicely for sequence diagrams but my experience with component diagrams is often...disappointing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A manifesto
&lt;/h2&gt;

&lt;p&gt;I was frustrated with what I was working on and had a couple of insights. Surely there should be some simple guidelines that guarantee pretty diagrams? So I made some notes and eventually came up with this list or rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Edge paths must travel across a "path grid"&lt;/li&gt;
&lt;li&gt;Node borders must be on the "path grid"&lt;/li&gt;
&lt;li&gt;Edges must meet nodes at "ports"&lt;/li&gt;
&lt;li&gt;Ports must sit on the "path grid"&lt;/li&gt;
&lt;li&gt;Where a port is not specified, layli may select a "default" port on any side of the node&lt;/li&gt;
&lt;li&gt;Nodes must be layed out so that the total area marked by the outside bounds of every node is as small as possible&lt;/li&gt;
&lt;li&gt;Nodes must be seperated by at least 1 space on the "path grid"&lt;/li&gt;
&lt;li&gt;Edges must must not cross!&lt;/li&gt;
&lt;li&gt;Edges must follow a grid path (ie. not curved or diagonal)&lt;/li&gt;
&lt;li&gt;Edges must be as short as possible&lt;/li&gt;
&lt;li&gt;Edges must have as few corners as possible&lt;/li&gt;
&lt;li&gt;Edge paths may sit on top of each other at the beginning or at the end&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think this is a reasonable start. It almost looks like a manifesto!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started on Layli
&lt;/h2&gt;

&lt;p&gt;After a little time prevaricating, I set out to clobber the keyboard a little and Layli slowly came in to being. The first thing I had to do was figure out how to arrange the boxes on my diagram (the nodes). I decided that the simplest way to do this was to just implement a primitive flow layout - just arrange them in to a square arrangement, row by column.&lt;/p&gt;

&lt;p&gt;Next up, I had to draw connections between the nodes (edges). To do this, I looked back to an blog that I read a couple years ago that described using &lt;a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm"&gt;Dijkstra's shortest path algorithm&lt;/a&gt; to plot paths between nodes. I forget the details but this seemed to be an intriguing approach. After a little work, I had something that looked pretty decent:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dnnrly/layli#an-example-diagram"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SLapgexK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/29j1mfiu5kk4gad92qvu.png" alt="Nodes laid out on a grid with connections between them" width="720" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a little more work, I was able to implement some more features. A handful of different node arrangements alongside trying to shuffle the order that we draw paths so we don't get crossing lines.&lt;/p&gt;

&lt;p&gt;There're more examples &lt;a href="https://github.com/dnnrly/layli/blob/master/examples/README.md"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What next
&lt;/h2&gt;

&lt;p&gt;I've got a few items on my &lt;a href="https://github.com/dnnrly/layli/issues"&gt;TODO list&lt;/a&gt;. Allowing you to specify nodes absolutely - giving them coordinates on your diagram, adding some styling, making the path-finding algorithm prettier. Who know's?&lt;/p&gt;

&lt;p&gt;Maybe this is something that you'd like to contribute to? Just &lt;a href="https://github.com/dnnrly/layli/issues/new/choose"&gt;raise an issue&lt;/a&gt; or a pull request and I'd be happy to take a look!&lt;/p&gt;

&lt;p&gt;Download &lt;a href="https://github.com/dnnrly/layli"&gt;layli&lt;/a&gt; and start using it now!&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>What will make me happy, as a #hacktoberfest maintainer</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Mon, 05 Oct 2020 20:54:21 +0000</pubDate>
      <link>https://dev.to/dnnrly/what-will-make-me-happy-as-a-hacktoberfest-maintainer-39f8</link>
      <guid>https://dev.to/dnnrly/what-will-make-me-happy-as-a-hacktoberfest-maintainer-39f8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The original version of this appeared as a tweet thread a few days ago:&lt;br&gt;
&lt;a href="https://twitter.com/pascaldoesgo/status/1311799941791133697?s=19"&gt;https://twitter.com/pascaldoesgo/status/1311799941791133697?s=19&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Hey #hacktoberfest beginners!
&lt;/h1&gt;

&lt;p&gt;I'm a very small scale maintainer and here are some things that you could do that I, personally, would value greatly! I suspect most maintainers would too. I personally look after 3 open source projects, essentially written to solve problems.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Shameless plug, here they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dnnrly/abbreviate"&gt;abbreviate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dnnrly/httpref"&gt;httpref&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dnnrly/s3backup"&gt;s3backup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, it's not much but it's mine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Deciding on a contribution
&lt;/h2&gt;

&lt;p&gt;First of all, I'd probably take a look at open issues on a project. A lot of projects will tag them with labels like &lt;code&gt;help wanted&lt;/code&gt; or &lt;code&gt;beginners&lt;/code&gt;. You can see quite quickly whether a project might have something they think is a good starting point for you. If you have an idea of what you could do to implement the change then just ask on the issue. I would happily spend a little time on feedback.&lt;/p&gt;

&lt;p&gt;If you think you have an idea for an entirely new change that doesn't already exist then raise your own issue to discuss it first. This has been called "talk first" or &lt;a href="https://dave.cheney.net/2019/02/18/talk-then-code"&gt;talk then code&lt;/a&gt; development. It'll help me understand what's coming in. And help me to give you some guidance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes can you make?
&lt;/h2&gt;

&lt;p&gt;4 1-line puntuation changes in separate PRs is  no help to anyone. I've had at 3 pull requests of this type already, including changes to the code of conduct and project license. The changes accidentally changed the legal meaning of the license text, moving it away from being the kind of project I want it to be. This is &lt;strong&gt;not&lt;/strong&gt; cool!&lt;/p&gt;

&lt;p&gt;Honest grammar and punctuation fixes are valued! If you've spent some time reviewing a README and you think you can make it better, then THANK YOU! I am a human and I old enough and had my ego punctured enough to realise that I make mistakes. All the time! If you spot something that you think isn't quite right the raise that PR.&lt;/p&gt;

&lt;p&gt;Adding and improving documentation is the best contribution! It's the bit most developers struggle with. Usage guides, installation instructions, FAQs. These are great candidates for documentation changes that always seem to need more work. Certainly for me, if I'm intimately familiar with a tool or some code then I find it harder to understand what it takes to start using it. An outside perspective is actually a great asset for this kind of contribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making that change
&lt;/h2&gt;

&lt;p&gt;Now this section is more about my personal style of contributing. It's an approach when extending my own projects as well as at work.&lt;/p&gt;

&lt;p&gt;First off open a draft PR early, fill out the PR template, make me aware of what you're doing. This achieves a few things all in one go.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Let's you use the CI/CD tooling where it's available. This depends very much on what the project is using to do their testing and deploying. It probably won't work for Github actions but might for Travis or CircleCI etc.&lt;/li&gt;
&lt;li&gt;Makes me aware of an incoming change.&lt;/li&gt;
&lt;li&gt;Gives me an opportunity to give you some early feedback for larger changes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I'm happy to review your code and help steer you if you don't feel confident or feel you just need some advice.&lt;/p&gt;

&lt;p&gt;You don't have to be a confident developer to start coding. I remember my first attempts at code. I didn't know what I was doing for a long time. To be fair, I still make it up a little now. 😅&lt;/p&gt;

&lt;h1&gt;
  
  
  What you can expect from me
&lt;/h1&gt;

&lt;p&gt;Be mindful that I have a full time job, small kids, a wife, people that call me on the phone, DIY, a laptop that we share amongst us.&lt;/p&gt;

&lt;p&gt;I'll try to help you as much as I can but I can't promise to be totally on it all the time.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;will&lt;/em&gt; take a look at all changes that come in a few days! If you've spent the time to raise a pull request then I owe it to you to give it the proper amount of attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want you to get something from #hacktoberfest
&lt;/h2&gt;

&lt;p&gt;Most importantly, have fun!&lt;/p&gt;

&lt;p&gt;I mean a free T-Shirt is all very nice but I want you to enjoy what you're doing. You'll be more engaged and find it easier to contribute.&lt;/p&gt;

&lt;p&gt;Ultimately #hacktoberfest is about building the Open Source community and joining in makes you a part of that.&lt;/p&gt;

</description>
      <category>hacktoberfest</category>
      <category>contributorswanted</category>
    </item>
    <item>
      <title>Introducing Abbreviationist</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Tue, 29 Sep 2020 22:19:38 +0000</pubDate>
      <link>https://dev.to/dnnrly/introducing-abbreviationist-1lfm</link>
      <guid>https://dev.to/dnnrly/introducing-abbreviationist-1lfm</guid>
      <description>&lt;p&gt;Just a bit of blatant self promotion here. I've been playing with my little CLI tool &lt;a href="https://github.com/dnnrly/abbreviate"&gt;abbreviate&lt;/a&gt; and wondering what I could do next. I also need to practice my very new front-end skills so I put together this site to meld the 2 things:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://abbreviationist.herokuapp.com/"&gt;https://abbreviationist.herokuapp.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not much but after so many years hiding in the backend, putting up a simple site with my own HTML and CSS is a big deal for me.&lt;/p&gt;

&lt;p&gt;If you have any comments or feedback then feel free to let me know. :)&lt;/p&gt;

</description>
      <category>go</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>Fun Coding</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Sat, 28 Mar 2020 21:15:09 +0000</pubDate>
      <link>https://dev.to/dnnrly/fun-coding-4a8n</link>
      <guid>https://dev.to/dnnrly/fun-coding-4a8n</guid>
      <description>&lt;p&gt;Fun Coding&lt;br&gt;
/verb/&lt;/p&gt;

&lt;p&gt;To develop code for ones own pleasure. This may or may not be related to your day job. Perhaps a side project, perhaps not. The principle is that it's for fun.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>life</category>
    </item>
    <item>
      <title>Rewarding Github contributions</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Tue, 10 Mar 2020 21:00:43 +0000</pubDate>
      <link>https://dev.to/dnnrly/rewarding-github-contributions-1pl4</link>
      <guid>https://dev.to/dnnrly/rewarding-github-contributions-1pl4</guid>
      <description>&lt;p&gt;So I'll probably be cross posting on Twitter or something but here goes...&lt;/p&gt;

&lt;p&gt;How do you reward people that take the time to contribute?&lt;/p&gt;

&lt;p&gt;I recently had someone fix a bug in &lt;a href="https://github.com/dnnrly/httpref"&gt;httpref&lt;/a&gt;. No prompting, just a PR out of the blue that nailed the problem. I was shocked, and surprised, and so so glad that someone had taken the time.&lt;/p&gt;

&lt;p&gt;Apart from a cursory 'thanks' when I hit merge and an impromptu shout out on Twitter I couldn't really do anything.&lt;/p&gt;

&lt;p&gt;Is this something that anyone has been able to do? Just show someone how much you appreciate what they've done?&lt;/p&gt;

&lt;p&gt;Discuss...&lt;/p&gt;

</description>
      <category>github</category>
      <category>community</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Learning Frontend as a Backend dev</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Thu, 27 Feb 2020 22:10:47 +0000</pubDate>
      <link>https://dev.to/dnnrly/learning-frontend-as-a-backend-dev-4hh5</link>
      <guid>https://dev.to/dnnrly/learning-frontend-as-a-backend-dev-4hh5</guid>
      <description>&lt;p&gt;Hey all, I thought I'd pull the community for tips on learning Frontend development.&lt;/p&gt;

&lt;p&gt;I've been writing backend software in various forms for many, many years now. Even so, Frontwnd feels magical and scary.&lt;/p&gt;

&lt;p&gt;It's definitely a skill I'm missing, but I wouldn't know where to start now.&lt;/p&gt;

&lt;p&gt;Has anyone done this particular journey? Any tips?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>react</category>
      <category>javascript</category>
      <category>vue</category>
    </item>
    <item>
      <title>THIS_IS_A_CONSTANT</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Thu, 27 Feb 2020 20:18:13 +0000</pubDate>
      <link>https://dev.to/dnnrly/thisisaconstant-3e2o</link>
      <guid>https://dev.to/dnnrly/thisisaconstant-3e2o</guid>
      <description>&lt;p&gt;A junior engineer asked a great question while we were pairing&lt;/p&gt;

&lt;p&gt;"Why does this variable have to be in upper case?"&lt;/p&gt;

&lt;p&gt;Well, because it's static final, of course.&lt;/p&gt;

&lt;p&gt;But why?&lt;/p&gt;

&lt;p&gt;So I had to think about this one and wondered why myself. What's so different? And why did people decide this was a good idea?&lt;/p&gt;

&lt;p&gt;So the obvious difference is that because it's final, it can't be modified after it has been initialised. And it's static, meaning that it's a property of the class and not of this instance.&lt;/p&gt;

&lt;p&gt;It's as close as you really get, in Java, to a const in other languages.&lt;/p&gt;

&lt;p&gt;But, he asked, why does that mean we have to make it upper case with underscores? Won't the compiler tell us when you try to change it?&lt;/p&gt;

&lt;p&gt;Well it's a convention that we used to tell us that we need to use this field differently, like we used to back in the old C days, and it's stuck from there.&lt;/p&gt;

&lt;p&gt;But what was so different about C?&lt;/p&gt;

&lt;p&gt;So there wasn't really the concept of a immutables for a while in C either. BUT we did have the #define directive. This told the compiler that the next thing it saw on the line would be a symbol that would be replaced exactly with the thing after that.&lt;/p&gt;

&lt;p&gt;So you would see something like:&lt;br&gt;
&lt;code&gt;#define STR "my string"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When the compiler saw STR, it would literally replace that symbol with "my string" when it was processing that file.&lt;/p&gt;

&lt;p&gt;It was important to know that you were dealing with something special, something that could break in REALLY weird ways! Anyone remember the old "end of file when ';' expected - but it's  RIGHT THERE!"?&lt;/p&gt;

&lt;p&gt;So here we are in 2020, writing Java variables with different case because it looks like a constant, because we have to know to treat it differently, almost with reverence, because of lessons learned in another language.&lt;/p&gt;

</description>
      <category>c</category>
      <category>java</category>
      <category>history</category>
    </item>
    <item>
      <title>Same post at the top of my feed</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Thu, 20 Feb 2020 23:51:55 +0000</pubDate>
      <link>https://dev.to/dnnrly/same-post-at-the-top-of-my-feed-3gin</link>
      <guid>https://dev.to/dnnrly/same-post-at-the-top-of-my-feed-3gin</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;I signed up tonight and clicked on a post to see what it's about. But now that article, as important and insightful as it is, appears at the top of my feed and I can't figure out how to remove it.&lt;/p&gt;

&lt;p&gt;Any suggestions?&lt;/p&gt;

</description>
      <category>help</category>
    </item>
    <item>
      <title>Testing Go CLI Tools</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Wed, 12 Feb 2020 21:08:19 +0000</pubDate>
      <link>https://dev.to/dnnrly/testing-go-cli-tools-4eic</link>
      <guid>https://dev.to/dnnrly/testing-go-cli-tools-4eic</guid>
      <description>&lt;h1&gt;
  
  
  Testing Go CLI Tools (part 1)
&lt;/h1&gt;

&lt;p&gt;This has all started from a very simple tweet from &lt;a href="https://twitter.com/matryer"&gt;Mat Ryer&lt;/a&gt;&lt;/p&gt;


&lt;blockquote class="twitter-tweet"&gt;
&lt;p&gt;I don’t use func main In &lt;a href="https://twitter.com/hashtag/golang?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#golang&lt;/a&gt; 😂&lt;br&gt;&lt;br&gt;But seriously, I always make a new little “run” function and then immediately call that, passing in args and io.Writer for stdout etc.&lt;br&gt;&lt;br&gt;It’s the easiest way I’ve found to make func main testable. &lt;a href="https://t.co/8BQ0EEmU5x"&gt;&lt;/a&gt;&lt;a href="https://t.co/8BQ0EEmU5x"&gt;https://t.co/8BQ0EEmU5x&lt;/a&gt;&lt;/p&gt;— mat_ryer.go (@matryer) &lt;a href="https://twitter.com/matryer/status/1227609908394287104?ref_src=twsrc%5Etfw"&gt;February 12, 2020&lt;/a&gt;
&lt;/blockquote&gt;  

&lt;p&gt;What is going on?&lt;/p&gt;

&lt;h2&gt;
  
  
  Interlude in to my testing journey
&lt;/h2&gt;

&lt;p&gt;So I have a confession to make - I like testing my code. I read about it first in &lt;a href="https://www.joelonsoftware.com/"&gt;Joel Spolsky’s&lt;/a&gt; book “Joel on Software”. Unit testing was a thing that I did a little 20 years ago when I was writing C for mobile phones and then C++ for Windows applications (before there were Apps). There was no common unit testing framework that people always looked to, we just cobbled it together with what we had.&lt;/p&gt;

&lt;p&gt;Then I moved to a company that did C# and discovered that there WERE frameworks for you to use. In this case, NUnit. Well, that was a revelation. Everything was tested, every code path and every combination of &lt;code&gt;if&lt;/code&gt; statement. It was great to feel like your code &lt;em&gt;worked&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Lets move forward a few years. Unit testing again in C++ with CPPUnit, meeting actual people whose full time job it was to test your software. I even learned some of the theory behind testing, passing a proper QA certification - &lt;a href="https://www.istqb.org/"&gt;ISTQB&lt;/a&gt;. Only the basic one mind, but it was a start. TDD became a thing that I tried and failed to do. Testing still involved all the code paths.&lt;/p&gt;

&lt;p&gt;So now we arrive at the present day. I’ve become less bad. I do TDD before I’ve even created the file that the Production code will go in. I test behaviours and not implementation. Occasionally I even make it so I can refactor my code without needing to change the tests. I’m not so worried about getting all of the code paths checked multiple times but I still care when there are gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing CLI tools
&lt;/h2&gt;

&lt;p&gt;It’s actually quite hard to test everything in a command line tool. When you think about it, how is a Unit Testing framework going to help you to parse command line arguments? What happens when some of the output goes to STDOUT? What about STDERR? And how do we get any kind of code coverage statistics?&lt;/p&gt;

&lt;h3&gt;
  
  
  BATS
&lt;/h3&gt;

&lt;p&gt;My first attempt at solving this uses a great framework called &lt;a href="https://github.com/bats-core/bats-core"&gt;BATS&lt;/a&gt;. This is essentially a Bash based Unit Testing framework. You can use this to to make calls to you CLI tool and validate the output. You can see how I’ve done this in a couple of places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/dnnrly/goclitem/blob/e9956a375c37de70a7874b7d78dfddc5c7ceea09/test/basic.bats"&gt;goclitem&lt;/a&gt;: a simple, opinionated, Go CLI application template&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/dnnrly/abbreviate/blob/a706c0471455f3b0908896f46a2f6991fa73bcb8/acceptance.bats"&gt;abbreviate&lt;/a&gt;: a tool for abbreviating long strings (it’s a pre-cursor to &lt;code&gt;goclitem&lt;/code&gt;, which is why the structure is a little different)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here we can see that I’m building the tool and then actually invoking it, testing my expectations against the real fully built tool. It’s great. BUT…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can’t check the code coverage&lt;/li&gt;
&lt;li&gt;We can’t use the nice testing tools that Go and 3rd party packages provide&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Calling &lt;code&gt;main()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This was the next obvious approach. This didn’t work that well. There was none of the control offered by the regular unit tests but there was difficulty intercepting the output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;run&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now we get on to Matt Ryer’s comment. What is it trying to do? Essentially this allows us to have an entry point to the CLI without having be locked in to &lt;code&gt;main&lt;/code&gt;. In part 2, I’ll dig in to how this is used.&lt;/p&gt;

</description>
      <category>go</category>
      <category>testing</category>
      <category>cli</category>
    </item>
    <item>
      <title>Go Interface Generation</title>
      <dc:creator>Pascal Dennerly</dc:creator>
      <pubDate>Fri, 26 Oct 2018 21:58:35 +0000</pubDate>
      <link>https://dev.to/dnnrly/go-interface-generation-34gg</link>
      <guid>https://dev.to/dnnrly/go-interface-generation-34gg</guid>
      <description>&lt;h1&gt;
  
  
  Go Interface Generation
&lt;/h1&gt;

&lt;p&gt;I’d like to rave about a tool that I discovered recently. But first…a little history.&lt;/p&gt;

&lt;p&gt;I’ve been working with &lt;a href="https://github.com/gobuffalo/buffalo"&gt;Buffalo&lt;/a&gt; and enjoying it very much. It’s all there in front of you, in Go (my very favourite language) and it’s easy to take your service from the basic out-of-the-box template to adding your own domain models and business logic.&lt;/p&gt;

&lt;p&gt;But I also have a background in Java of the Big Business kind. We’re talking full &lt;a href="https://en.wikipedia.org/wiki/Domain-driven_design"&gt;DDD&lt;/a&gt; and &lt;a href="https://www.techopedia.com/definition/24306/three-tier-application"&gt;3-tier applications&lt;/a&gt; in web containers, JCA components and fancy messaging solutions.&lt;/p&gt;

&lt;p&gt;Now the thing I like about 3-tier applications is the strong seperation of concerns. Buffalo, as easy as it is, doesn’t have this same seperation. Buffalo deals with this by making strong use of integration tests using a full database implementation and utilities to manage database schemas and populating the database with data according to what is defined in your text fixtures.&lt;/p&gt;

&lt;p&gt;In short, I want to be able to take the business logic out of the handler and put it in a repository that I can abstract away so that when I do my testing (first), I can make sure that I’m only testing 1 thing at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do we achieve this in Buffalo?
&lt;/h2&gt;

&lt;p&gt;Well the obvious way is to move the logic for making queries against the database in to its own type, passing in the dependencies as members of this class. Stub out the dependencies - a route for validating outputs against the inputs that we insert.&lt;/p&gt;

&lt;p&gt;Buffalo makes extensive use of the incredibly useful package &lt;a href="https://github.com/gobuffalo/pop"&gt;Pop&lt;/a&gt;. Unfortunately, access to the database in this package is via the &lt;a href="https://godoc.org/github.com/gobuffalo/pop#Connection"&gt;Connection&lt;/a&gt; type. It’s unfortunate because it is a &lt;code&gt;struct&lt;/code&gt;, which means that we can’t just insert a mock version of it in to the units that we’d like to test.&lt;/p&gt;

&lt;p&gt;To perform this injection of a mock, we need to create an interface that exposes each of the exported functions on the &lt;code&gt;Connection&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;After a little searching, I found &lt;a href="//github.com/vburenin/ifacemaker"&gt;&lt;code&gt;ifacemaker&lt;/code&gt;&lt;/a&gt;. This tools reads the struct and creates an interface that allows access to each of the exported functions on that type.&lt;/p&gt;

&lt;p&gt;To run the tool, I did this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ifacemaker --file ~/go/src/github.com/gobuffalo/pop/connection.go --struct Connection --iface DBConnection --pkg repo

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This presented the following type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight mosel"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;

&lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;DBConnection&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DBConnection&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;MigrationURL&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;
        &lt;span class="n"&gt;MigrationURL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;MigrationTableName&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;track&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;
        &lt;span class="n"&gt;MigrationTableName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Open&lt;/span&gt; &lt;span class="n"&gt;creates&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
        &lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Close&lt;/span&gt; &lt;span class="n"&gt;destroys&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
        &lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;If&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;rolled&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;NewTransaction&lt;/span&gt; &lt;span class="n"&gt;starts&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
        &lt;span class="n"&gt;NewTransaction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(*&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Rollback&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt; &lt;span class="n"&gt;rollback&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regardless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;useful&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="n"&gt;Rollback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt; &lt;span class="n"&gt;creates&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="s2"&gt;"empty"&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;
        &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;TruncateAll&lt;/span&gt; &lt;span class="n"&gt;truncates&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt;
        &lt;span class="n"&gt;TruncateAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now use this in our Go mocking tools - for example &lt;a href="https://github.com/stretchr/testify/"&gt;&lt;code&gt;github.com/stretchr/testify/mock&lt;/code&gt;&lt;/a&gt;. But if we’re going to use a mock, we have to generate one. Here’s where we turn to &lt;a href="https://github.com/vektra/mockery/"&gt;mockery&lt;/a&gt;. The first time you use it - it’ll fail. This is because it doesn’t populate the package imports and package names (for example, &lt;code&gt;Connection&lt;/code&gt; rather than &lt;code&gt;pop.Connection&lt;/code&gt;). Fortunately this is easy to fix, giving this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight mosel"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;

&lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;"github.com/gobuffalo/pop"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;DBConnection&lt;/span&gt; &lt;span class="n"&gt;represents&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;Buffalo&lt;/span&gt; &lt;span class="n"&gt;pop&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;database&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;DBConnection&lt;/span&gt; &lt;span class="n"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;MigrationURL&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;
    &lt;span class="n"&gt;MigrationURL&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;MigrationTableName&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;track&lt;/span&gt; &lt;span class="n"&gt;migrations&lt;/span&gt;
    &lt;span class="n"&gt;MigrationTableName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Open&lt;/span&gt; &lt;span class="n"&gt;creates&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
    &lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Close&lt;/span&gt; &lt;span class="n"&gt;destroys&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
    &lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="k"&gt;If&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="n"&gt;an&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;rolled&lt;/span&gt; &lt;span class="n"&gt;back&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;otherwise&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;NewTransaction&lt;/span&gt; &lt;span class="n"&gt;starts&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;
    &lt;span class="n"&gt;NewTransaction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(*&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Rollback&lt;/span&gt; &lt;span class="n"&gt;will&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;automatically&lt;/span&gt; &lt;span class="n"&gt;rollback&lt;/span&gt; &lt;span class="n"&gt;that&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;when&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;regardless&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;can&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;useful&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;Rollback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;Q&lt;/span&gt; &lt;span class="n"&gt;creates&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="s2"&gt;"empty"&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="n"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;
    &lt;span class="p"&gt;//&lt;/span&gt; &lt;span class="n"&gt;TruncateAll&lt;/span&gt; &lt;span class="n"&gt;truncates&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;datasource&lt;/span&gt;
    &lt;span class="n"&gt;TruncateAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The next time we run &lt;code&gt;mockery&lt;/code&gt;, it magically works. Take a look at this snippet, if it compiles then you have yourself an interface over a &lt;code&gt;struct&lt;/code&gt; to unlock your unit tests.&lt;/p&gt;

&lt;p&gt;The following code &lt;em&gt;should&lt;/em&gt; work, although you may need to fill in the blanks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
func AcceptConnection(tx DBConnection) {}

func TestMocks(t *testing.T) {
    tx := &amp;amp;pop.Connection{}
    mx := &amp;amp;mocks.DBConnection{}

    AcceptConnection(tx)
    AcceptConnection(mx)
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you get this far then you have all of the components needed to add a testable repository tier in your Buffalo app.&lt;/p&gt;

</description>
      <category>go</category>
      <category>buffalo</category>
      <category>domaindrivendesign</category>
    </item>
  </channel>
</rss>
