<?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: Ryan Hansen</title>
    <description>The latest articles on DEV Community by Ryan Hansen (@ketiko).</description>
    <link>https://dev.to/ketiko</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%2F387144%2Fbe5bf794-6ec0-46e5-997a-c00c9f10afb7.jpeg</url>
      <title>DEV Community: Ryan Hansen</title>
      <link>https://dev.to/ketiko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ketiko"/>
    <language>en</language>
    <item>
      <title>How to replicate a remote Postgres DB locally</title>
      <dc:creator>Ryan Hansen</dc:creator>
      <pubDate>Sat, 16 May 2020 20:12:29 +0000</pubDate>
      <link>https://dev.to/ketiko/how-to-replicate-a-remote-postgres-db-locally-4khf</link>
      <guid>https://dev.to/ketiko/how-to-replicate-a-remote-postgres-db-locally-4khf</guid>
      <description>&lt;p&gt;There have been times when I've wanted an exact copy of a database locally. If I'm writing a particularly complex database migration, it's nice to have a clone of a QA environment with sample data.&lt;/p&gt;

&lt;p&gt;This is super easy using the &lt;a href="https://www.postgresql.org/docs/current/reference-client.html"&gt;postgres client&lt;/a&gt; tools. You can stream the remote database directly into your local one!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; I always start with a fresh database locally to avoid any synchronization errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;$'&lt;/span&gt;&lt;span class="se"&gt;\n\t&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;

&lt;span class="nv"&gt;USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres
&lt;span class="nv"&gt;HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost
&lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5432
&lt;span class="nv"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres

&lt;span class="nv"&gt;REMOTE_DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgres://user:pass@host:port

dropdb &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="nv"&gt;$HOST&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PORT&lt;/span&gt; &lt;span class="nv"&gt;$DB&lt;/span&gt;
createdb &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="nv"&gt;$HOST&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PORT&lt;/span&gt; &lt;span class="nv"&gt;$DB&lt;/span&gt;
pg_dump &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="nt"&gt;--clean&lt;/span&gt; &lt;span class="nt"&gt;--no-acl&lt;/span&gt; &lt;span class="nt"&gt;--no-owner&lt;/span&gt; &lt;span class="nt"&gt;--if-exists&lt;/span&gt; &lt;span class="nv"&gt;$REMOTE_DATABASE_URL&lt;/span&gt; | psql 
&lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;ON_ERROR_STOP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;on &lt;span class="nv"&gt;$DB&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="nv"&gt;$HOST&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PORT&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nv"&gt;$USER&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"CATS: ALL YOUR *DATABASE* ARE BELONG TO US"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now you can test your migrations over and over, resetting as you need, from the remote database!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
    </item>
    <item>
      <title>Becoming Homeless</title>
      <dc:creator>Ryan Hansen</dc:creator>
      <pubDate>Sat, 16 May 2020 05:00:18 +0000</pubDate>
      <link>https://dev.to/ketiko/becoming-homeless-336i</link>
      <guid>https://dev.to/ketiko/becoming-homeless-336i</guid>
      <description>&lt;p&gt;The other day at work I was doing something and accidentally made a folder named tilde.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt;
~ bin lib spec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Oops, well I guess I should remove that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rm -r ~
rm: remove write-protected regular file .ssh/config?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Wait… what?!&lt;/strong&gt; Oh crap, did that just delete my home directory?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ls ~
total 0
drwxr-xr-x 17 user group  544 Apr  18 11:45 .
drwxr-xr-x 27 user group  864 Apr  18 10:18 ..
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lucky I have rdiff-backup run weekly.  I changed that to &lt;em&gt;daily&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Note to self, run &lt;code&gt;rm -r ./~&lt;/code&gt; next time.&lt;/p&gt;

&lt;p&gt;Man what a day.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>linux</category>
    </item>
    <item>
      <title>Enforcing Java Coding Styles</title>
      <dc:creator>Ryan Hansen</dc:creator>
      <pubDate>Sat, 16 May 2020 04:43:38 +0000</pubDate>
      <link>https://dev.to/ketiko/enforcing-java-coding-styles-1a9</link>
      <guid>https://dev.to/ketiko/enforcing-java-coding-styles-1a9</guid>
      <description>&lt;p&gt;In any large organization there is often a desire to be able to move engineers between teams and projects. Having a consistent coding style will often make that easier.  There are several reasons for this and many &lt;a href="https://tylerthehaas.com/blog/automating-your-style-guide"&gt;people&lt;/a&gt; have articulated them far better than I could. I'll assume you already have or want to begin using a style guide.&lt;/p&gt;

&lt;p&gt;I'm a firm believer that if you are going to have a style guide you have to enforce it. As engineers, we automate everything. Manually spot-checking pull-requests to ensure consistency is fraught with errors. If you are going to enforce it, then you should make it as easy as possible through tooling. Engineers should not be spending their time formatting &lt;code&gt;if&lt;/code&gt; blocks or sorting &lt;code&gt;import&lt;/code&gt; statements. We want to enforce that style but not make it time-consuming.&lt;/p&gt;

&lt;p&gt;The Ruby language has a pretty standard &lt;a href="https://rubystyle.guide/"&gt;style guide&lt;/a&gt;.  There is a great CLI tool called &lt;a href="https://docs.rubocop.org/en/stable/"&gt;Rubocop&lt;/a&gt; that will check against this style guide for violations. But my favorite part of Rubocop is &lt;code&gt;rubocop --auto-correct&lt;/code&gt;. This command will fix almost all of your violations for you every time.&lt;/p&gt;

&lt;p&gt;Java has something similar. One of the most widely used style guides is from &lt;a href="https://google.github.io/styleguide/javaguide.html"&gt;Google&lt;/a&gt;. You can use &lt;a href="https://github.com/coveooss/fmt-maven-plugin"&gt;fmt-maven-plugin&lt;/a&gt; to check for violations. And just like Rubocop, it can auto-correct some of your code for you by running &lt;code&gt;mvn com.coveo:fmt-maven-plugin:format&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are several other static analysis tools in Java. Some of my favorites are &lt;a href="https://maven.apache.org/plugins/maven-pmd-plugin/usage.html"&gt;maven-pmd-plugin&lt;/a&gt;, &lt;a href="https://maven.apache.org/plugins/maven-checkstyle-plugin/"&gt;maven-checkstyle-plugin&lt;/a&gt;, and &lt;a href="https://spotbugs.github.io/spotbugs-maven-plugin/"&gt;spotbugs-maven-plugin&lt;/a&gt;. I won't deep dive into any of these tools, but I highly recommend you take a look at them.&lt;/p&gt;

&lt;p&gt;Getting back on track...&lt;/p&gt;

&lt;p&gt;Ok, so we have a style guide. We have lots of tools to check it, automate auto-corrections, and analyze for other inconsistencies. So what now?&lt;/p&gt;

&lt;p&gt;As always, your CI is a great place to enforce it!&lt;/p&gt;

&lt;p&gt;Here is a sample bash script I use. It will return a non-zero exit code if any of the commands inside it fail.  This makes it perfect to throw into any CI flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eo&lt;/span&gt; pipefail

mvn &lt;span class="nb"&gt;fmt&lt;/span&gt;:check
mvn checkstyle:check
mvn pmd:check
mvn spotbugs:check
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/mohanpedala"&gt;mohanpedala&lt;/a&gt; has a &lt;a href="https://gist.github.com/mohanpedala/1e2ff5661761d3abd0385e8223e16425#set--e--u--o-pipefail"&gt;great explanation&lt;/a&gt; of &lt;code&gt;set -eo pipefail&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Locally you can setup a &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks"&gt;git hook&lt;/a&gt; to run &lt;code&gt;mvn com.coveo:fmt-maven-plugin:format&lt;/code&gt; so that you auto-correct some styles before you even push changes.&lt;/p&gt;

&lt;p&gt;Here is a sample pom.xml with these configured...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.coveo&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;fmt-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.9&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;sourceDirectory&amp;gt;&lt;/span&gt;src/main/java/com/ketiko&lt;span class="nt"&gt;&amp;lt;/sourceDirectory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;testSourceDirectory&amp;gt;&lt;/span&gt;src/test&lt;span class="nt"&gt;&amp;lt;/testSourceDirectory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;google&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;format&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-pmd-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.12.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;verbose&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/verbose&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.maven.plugins&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;maven-checkstyle-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.1.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;configLocation&amp;gt;&lt;/span&gt;google_checks.xml&lt;span class="nt"&gt;&amp;lt;/configLocation&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;consoleOutput&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/consoleOutput&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;failOnViolation&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/failOnViolation&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;failsOnError&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/failsOnError&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;includeTestSourceDirectory&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/includeTestSourceDirectory&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;linkXRef&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/linkXRef&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;logViolationsToConsole&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/logViolationsToConsole&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;violationSeverity&amp;gt;&lt;/span&gt;warning&lt;span class="nt"&gt;&amp;lt;/violationSeverity&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;suppressionsLocation&amp;gt;&lt;/span&gt;
            checkstyle-suppressions.xml
        &lt;span class="nt"&gt;&amp;lt;/suppressionsLocation&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.github.spotbugs&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spotbugs-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.1.12&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;** &lt;strong&gt;Update&lt;/strong&gt; **&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/elmuerte"&gt;elmuerte&lt;/a&gt; brought up an &lt;a href="https://dev.to/elmuerte/comment/p41j"&gt;excellent point&lt;/a&gt; in the comments that I wanted to reply to. Maven has several &lt;a href="https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#lifecycle-reference"&gt;&lt;em&gt;phases&lt;/em&gt;&lt;/a&gt; during its build process. The &lt;strong&gt;verify&lt;/strong&gt; phase is described as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Run any checks to verify the package is valid and meets quality criteria.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using this you can run a single maven command in your CI, &lt;code&gt;mvn verify&lt;/code&gt;. Simply update those plugins to run during that phase and you are all set! This is an excellent way to accomplish the same thing.&lt;/p&gt;

&lt;p&gt;However, maven phases run in order. That means that &lt;em&gt;verify&lt;/em&gt; runs after the &lt;em&gt;test&lt;/em&gt; phase.  I like to run the quality checks first thing in my CI without waiting for my test suite to complete. &lt;/p&gt;

&lt;p&gt;You could just run those &lt;em&gt;goals&lt;/em&gt; individually in your CI as well, without the bash script. When I wanted to run them locally I kept forgetting all the checks I had configured in the CI. So I created the bash script to quickly run them locally and reuse it on the CI.&lt;/p&gt;

</description>
      <category>java</category>
      <category>codequality</category>
      <category>maven</category>
    </item>
  </channel>
</rss>
