<?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: David Owens</title>
    <description>The latest articles on DEV Community by David Owens (@fig-rolls).</description>
    <link>https://dev.to/fig-rolls</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3163756%2F51315594-e876-4265-affa-75e8a2c88bf1.png</url>
      <title>DEV Community: David Owens</title>
      <link>https://dev.to/fig-rolls</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fig-rolls"/>
    <language>en</language>
    <item>
      <title>paint pictures like a 5 year old</title>
      <dc:creator>David Owens</dc:creator>
      <pubDate>Fri, 24 Oct 2025 23:21:20 +0000</pubDate>
      <link>https://dev.to/fig-rolls/paint-pictures-like-a-5-year-old-3olo</link>
      <guid>https://dev.to/fig-rolls/paint-pictures-like-a-5-year-old-3olo</guid>
      <description>&lt;p&gt;Do you ever find yourself in a design or planning meeting with loads of talking heads, all confidently agreeing on important points, where it's almost like the conclusions are just a matter of fact and should be obvious to anyone?&lt;/p&gt;

&lt;p&gt;Yet you leave the meeting feeling unsettled, you sense gaps in the plan filled with vague arm wavey "someone will do something here" or a design that seems to hinge off a "decision engine" the details of which "we'll work out in the implementation."&lt;/p&gt;

&lt;p&gt;So you ask around a bit, but no one seems to actually be able to coherently explain what the fuzzy stuff will actually be, what it will do, or even who is doing it.&lt;/p&gt;

&lt;p&gt;"I need someone to paint me a picture to understand all this." you say to yourself. &lt;/p&gt;

&lt;p&gt;Well guess what, they probably won't.&lt;/p&gt;

&lt;p&gt;JFDI yourself, following these 2 rules: &lt;/p&gt;




&lt;h3&gt;
  
  
  1. Be positively unfussy about it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;boxes &lt;strong&gt;shouldn't&lt;/strong&gt; line up neatly&lt;/li&gt;
&lt;li&gt;labels &lt;strong&gt;should&lt;/strong&gt; definitely have &lt;strong&gt;typos&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;use crayons&lt;/strong&gt; if your kids haven't pushed them up their nose&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It musn't be good looking&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Do not leave gaps
&lt;/h3&gt;

&lt;p&gt;Put &lt;strong&gt;your&lt;/strong&gt; best interpretation of what the vague fuzzy stuff is into it. Even though you know you've got it wrong, just put it in.&lt;/p&gt;




&lt;p&gt;Then present it back, to everyone.&lt;br&gt;
Could be in the next meeting, an e-mail or paste it in the project Slack channel. Much like a 5 year old with their latest drawing, get it stuck under everyone's nose who you think might be interested and even those who are not.&lt;/p&gt;

&lt;p&gt;If you are lucky, human nature will take over, an image that challenges a person's view seems to get much more of an immediate reaction than the written word.&lt;/p&gt;

&lt;p&gt;The "someone will do something here" was "my guys will sort this with a perl script in 2 days" to the ops manager, meanwhile the project manager was talking to a recruiter about getting 4 contractors in.&lt;/p&gt;

&lt;p&gt;It turns out the "decision engine" was assumed to be a 3 month procurement piece and integration with a SaaS offering to the product manager while one engineer had it down as 14 lines of code in an existing class.&lt;/p&gt;

&lt;p&gt;The slightly less confident conversations sparked are great.&lt;/p&gt;

&lt;p&gt;But the even better part is, having used crayons, no one will ever trust you with diagramming anything again and immediately someone else will take responsibility to draw your picture up in a "proper tool". &lt;/p&gt;

&lt;p&gt;Happy days&lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>projectmanagement</category>
    </item>
    <item>
      <title>listing over to the top right</title>
      <dc:creator>David Owens</dc:creator>
      <pubDate>Wed, 24 Sep 2025 20:15:34 +0000</pubDate>
      <link>https://dev.to/fig-rolls/listing-over-to-the-top-right-35f7</link>
      <guid>https://dev.to/fig-rolls/listing-over-to-the-top-right-35f7</guid>
      <description>&lt;p&gt;I have no idea why but for some reason I've taken to using Thunderbird as my e-mail client on my "new to me" mac.&lt;/p&gt;

&lt;p&gt;When you do a search in Thunderbird for some keyword(s) the results that are returned have limited interactivity, sure there's a nice histogram with the volume of the e-mails found plotted over time, but can you do anything useful like... delete them? &lt;/p&gt;

&lt;p&gt;Nope, but fear not, apparently you just need the results in a "list". I thought it already looked "listy", but there's a link in the top right to "show results as list", this allows an even more "listified" view of the results to be rendered in a new tab. &lt;/p&gt;

&lt;p&gt;This option evaded me for way too long (&lt;a href="https://support.mozilla.org/en-US/questions/1401708" rel="noopener noreferrer"&gt;and others don't seem super happy with it&lt;/a&gt;), but for now I can happily bulk select and trash.&lt;/p&gt;

&lt;p&gt;Good night&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>thunderbird</category>
    </item>
    <item>
      <title>renaming things is hard also</title>
      <dc:creator>David Owens</dc:creator>
      <pubDate>Thu, 05 Jun 2025 17:22:54 +0000</pubDate>
      <link>https://dev.to/fig-rolls/renaming-things-is-hard-also-36jc</link>
      <guid>https://dev.to/fig-rolls/renaming-things-is-hard-also-36jc</guid>
      <description>&lt;p&gt;By default docker compose uses the directory name the compose yaml resides in as a project name to prefix to any named volumes.&lt;/p&gt;

&lt;p&gt;So given:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;home
|_fig-rolls
  |_projects
    |_awesome
      |_docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;docker-compose.yml&lt;/code&gt; defining a database server I can use where (I hoped) the initial import of a large database dump is persisted between containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;percona/percona-server:8.4&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;percona-server&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3306:3306"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_ROOT_PASSWORD}&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;not_so_awesome&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_USER}&lt;/span&gt;
      &lt;span class="na"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_PASSWORD}&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;percona-data:/var/lib/mysql&lt;/span&gt;              &lt;span class="c1"&gt;# Database data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;percona-logs:/var/log/mysql&lt;/span&gt;              &lt;span class="c1"&gt;# MySQL logs&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;percona-backups:/backups&lt;/span&gt;                 &lt;span class="c1"&gt;# XtraBackup output&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;${PWD}/data/not_so_awesome.sql.gz:/docker-entrypoint-initdb.d/not_so_awesome.sql.gz&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;percona-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;percona-logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;percona-backups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You end up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker volume ls | grep awesome
local     awesome_percona-backups
local     awesome_percona-data
local     awesome_percona-logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Should be good to &lt;code&gt;docker compose down&lt;/code&gt;, all my data is safe in &lt;code&gt;awesome_percona-data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of course I only learned this &lt;strong&gt;after&lt;/strong&gt; I renamed my project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mv /home/fig-rolls/projects/awesome /home/fig-rolls/projects/not_so_awesome&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Bring a new container up and of course it's created and mounted an &lt;strong&gt;empty&lt;/strong&gt; &lt;code&gt;not_so_awesome_percona-data&lt;/code&gt; volume.&lt;/p&gt;

&lt;p&gt;It's obvious really, what-else would Docker use to name the volumes to avoid conflicts with other projects?&lt;/p&gt;

&lt;p&gt;Never mind, not that long to reimport from an existing DB dump (used the time to write this.)&lt;/p&gt;

&lt;p&gt;It's worth noting you can &lt;a href="https://docs.docker.com/reference/compose-file/volumes/#name" rel="noopener noreferrer"&gt;specify your own volume name&lt;/a&gt; which will then not get this project prefix and remain consistent.&lt;/p&gt;

&lt;p&gt;And of course the old volumes were actually still there so I could have just &lt;a href="https://stackoverflow.com/questions/73053406/docker-volume-rename-or-copy-operation" rel="noopener noreferrer"&gt;jumped through hoops&lt;/a&gt; to copy the contents to the newly named volumes (there's weirdly no option to rename.)&lt;/p&gt;

&lt;p&gt;Hope this was useful.&lt;/p&gt;

&lt;p&gt;Thanks for reading and don't make the same mistake :)&lt;/p&gt;

</description>
      <category>docker</category>
      <category>database</category>
      <category>backup</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>curl, it's got u</title>
      <dc:creator>David Owens</dc:creator>
      <pubDate>Wed, 14 May 2025 21:34:43 +0000</pubDate>
      <link>https://dev.to/fig-rolls/curl-its-got-u-1l8h</link>
      <guid>https://dev.to/fig-rolls/curl-its-got-u-1l8h</guid>
      <description>&lt;p&gt;I like &lt;a href="https://curl.se/" rel="noopener noreferrer"&gt;curl&lt;/a&gt; it's available as a command line tool and is pretty ubiquitous across platforms.&lt;/p&gt;

&lt;p&gt;This allows me to compose a http request against a test environment, check everything worked as expected and then copy that request from my terminal with the intent of running on production.&lt;/p&gt;

&lt;p&gt;Easy - it's all just plain text now, do a find-and-replace on the hostname and it's ready to go!&lt;/p&gt;

&lt;p&gt;Here's a hypothetical I've prepared featuring some very important resources I'm going to alter.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -X DELETE https://prod.server.net/fig-rolls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However an interface like that should want to authenticate who is conducting such a privileged operation. For this, many still use &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Authentication#basic_authentication_scheme" rel="noopener noreferrer"&gt;Basic Auth&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Basic Auth just needs me to base64 encode the username and password and pop it in the Authorization header, so I'll just grab the password out of the secrets management system and do that...&lt;/p&gt;

&lt;p&gt;&lt;code&gt;echo 'admin:p4ssw0rd' | base64&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;(Glad we're spending 5K a year on Vault to protect that /s) &lt;/p&gt;

&lt;p&gt;OK, it's ready:&lt;br&gt;
&lt;code&gt;curl -H 'Authorization: YWRtaW46cDRzc3cwcmQK' -X DELETE https://prod.server.net/fig-rolls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To get that run in production it might require me to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;send it to a colleague&lt;/li&gt;
&lt;li&gt;commit to a git repository&lt;/li&gt;
&lt;li&gt;document in some implementation plan (change management)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You really don't want to put that Authorization header value in any of those. &lt;br&gt;
&lt;code&gt;echo YWRtaW46cDRzc3cwcmQK | base64 --decode&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;Yeah, no.&lt;/p&gt;

&lt;p&gt;But here curl can help you, with -u, you --user you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl -u admin -X DELETE https://prod.server.net/fig-rolls&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note there is no secret or encoding of a secret in the command, instead, you get an interactive prompt!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Enter host password for user 'admin':&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;No longer do you have to instruct someone (or future you) how to encode the password and modify the curl command. Just retrieve it when needed and supply to the prompt, curl takes care of the encoding and addition of the header for you.&lt;/p&gt;

&lt;p&gt;OK I'm off to rotate that password above now. Get some special characters in it and make it longerer. &lt;/p&gt;

&lt;p&gt;Here we go: &lt;code&gt;.$@[BD:O]_'=M0H;mzkgLOUr1&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;And yes, here we have another nice benefit of using the interactive prompt. I no longer have to worry about escaping that lot &lt;strong&gt;correctly&lt;/strong&gt; in a shell.&lt;/p&gt;

&lt;p&gt;There are other benefits to avoiding secrets being present in any commands you are running in a shell, more knowledgable people feel free to chime in on the comments.&lt;/p&gt;

&lt;p&gt;If you want to know more around authentication with curl this is an excellent summary of options available including alternate schemes to Basic Auth and how to authenticate against proxies.&lt;br&gt;
&lt;a href="https://everything.curl.dev/http/auth.html" rel="noopener noreferrer"&gt;https://everything.curl.dev/http/auth.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>curl</category>
      <category>http</category>
      <category>security</category>
    </item>
  </channel>
</rss>
