<?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>Forem: Erik Pischel</title>
    <description>The latest articles on Forem by Erik Pischel (@erikpischel).</description>
    <link>https://forem.com/erikpischel</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%2F55449%2F36a91856-2126-4965-b85a-92ccd84dfff8.jpg</url>
      <title>Forem: Erik Pischel</title>
      <link>https://forem.com/erikpischel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/erikpischel"/>
    <language>en</language>
    <item>
      <title>Implementing a simple sudoku solver</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sun, 19 Nov 2023 09:29:03 +0000</pubDate>
      <link>https://forem.com/erikpischel/implementing-a-simple-sudoku-solver-2kod</link>
      <guid>https://forem.com/erikpischel/implementing-a-simple-sudoku-solver-2kod</guid>
      <description>&lt;p&gt;The other day I thought about whether it would take a “while” for a computer to solve a sudoku puzzle using a naiive brute-force algorithm. I set out to find out.&lt;/p&gt;

&lt;p&gt;In this article I use my bread-and-butter programming language Java to create such a solver in a kind of test driven way and also explore some simple optimizations.&lt;/p&gt;

&lt;p&gt;Implementation idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use a backtracking algorithm, that means recursively go from cell to cell on the puzzle board and fill in numbers from 1 to 9 and check if all rules are satisfied. For example:

&lt;ol&gt;
&lt;li&gt;It starts with top left, fill in “1”. All rules satisfied – got to the next.&lt;/li&gt;
&lt;li&gt;Fill in “1” – two 1s in a row – try with “2”, all rules satisfied, go to the next. And so on.&lt;/li&gt;
&lt;li&gt;If in a cell no number satisfy the rules, go back to the previous cell and try the next number there.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;The puzzle board is represented as a 2-dimensional array.&lt;/li&gt;
&lt;li&gt;The number “0” represents an empty cell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recap of the sudoku rules: In all horizontal and all vertical lines the numbers 1 to 9 are filled in exactly once plus in each 3×3 “subsquare” / “subboard” the numbers 1 to 9 are filled in exactly once.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: The Solver accepts an already completed board
&lt;/h1&gt;

&lt;p&gt;When the board is already filled out, the Solver returns the board. It does not check if the board is correctly filled out. The following test checks this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
    public void fineWithFilledMatrix() {
        final int[][] matrix = new int[9][9];
        for(int i = 0; i &amp;lt; matrix.length; i++) {
            for (int j = 0; j &amp;lt; matrix[i].length; j++) {
                matrix[i][j] = 1;
            }
        }
        matrix[0][0] = 5;
        System.out.println(Solver.matrixToString(matrix));
        final var result = new Solver().nextField(0, 0, matrix);
        System.out.println(Solver.matrixToString(matrix));
        final int[][] expected = new int[9][9];
        for(int i = 0; i &amp;lt; expected.length; i++) {
            for (int j = 0; j &amp;lt; expected[i].length; j++) {
                expected[i][j] = 1;
            }
        }
        expected[0][0] = 5;
        Assert.assertFalse(result.isEmpty());
        Assert.assertArrayEquals(expected, result.get());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It creates a board (I call this “matrix” here) and fills it with “ones” except for the very first cell which gets a 5. It feeds it to the solver and checks whether it gets it back as solved.&lt;/p&gt;

&lt;p&gt;Here is the code that accomplishes it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package de.epischel.hello.sudoku;

import java.util.Optional;

public class Solver {

    public Optional&amp;lt;int[][]&amp;gt; nextField(int x, int y, int[][] matrix) {
        if (y==9 &amp;amp;&amp;amp; x == 0) {
            return Optional.of(matrix);
        }
        if (matrix[y][x]&amp;gt;0) {
            int nextX = x&amp;lt;8?x+1:0;
            int nextY = x&amp;lt;8?y:y+1;
            return nextField(nextX, nextY, matrix);
        }
        return Optional.empty();
    }

    public static String matrixToString(int[][] matrix) {
        StringBuilder sb = new StringBuilder();
        for(int y = 0; y &amp;lt; matrix.length; y++) {
            for(int x=0; x &amp;lt; matrix[y].length; x++) {
                sb.append(" ").append(matrix[y][x]).append(" ");
            }
            sb.append("\n");
        }
        return sb.toString();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The method “nextField” takes the current coordinates x and y and the matrix aka the board. It first checks whether it is just outside the board which means the board has been filled out. If so it returns the board. Otherwise if the current cell is already filled in, it recursivly calls the next cell. If the the current cell is not filled in, it returns an empty Optional, indicating it can’t fill in the cell.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Adding the “horizontal rule”
&lt;/h1&gt;

&lt;p&gt;Next we want to actually fill in numbers into an empty cell and check against the rule, that each row has pairwise distinct numbers in it.&lt;/p&gt;

&lt;p&gt;First, here is the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Test
    public void followRuleHorizontal() {
        final int[][] matrix = new int[9][9];
        for(int i = 0; i &amp;lt; matrix.length; i++) {
            for (int j = 0; j &amp;lt; matrix[i].length; j++) {
                matrix[i][j] = j+1;
            }
        }
        matrix[0][3] = 0;
        matrix[0][4] = 0;
        matrix[5][5] = 0;
        matrix[5][7] = 0;
        System.out.println(Solver.matrixToString(matrix));
        final var result = new Solver().solve(matrix);
        System.out.println(Solver.matrixToString(matrix));
        final int[][] expected = new int[9][9];
        for(int i = 0; i &amp;lt; expected.length; i++) {
            for (int j = 0; j &amp;lt; expected[i].length; j++) {
                expected[i][j] = j+1;
            }
        }
        Assert.assertFalse(result.isEmpty());
        Assert.assertArrayEquals(expected, result.get());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It creates a board with each row numbers incrementally from one to nine and then “blanks” four cells. The solver should fill these cells with the correct numbers. Here is how it’s done (note: I introduce a “solve” method):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public Optional&amp;lt;int[][]&amp;gt; solve(int[][] matrix) {
        return nextField(0,0,matrix);
    }

    public Optional&amp;lt;int[][]&amp;gt; nextField(int x, int y, int[][] matrix) {
        if (y==9 &amp;amp;&amp;amp; x == 0) {
            return Optional.of(matrix);
        }
        if (matrix[y][x]&amp;gt;0) {
            int nextX = x&amp;lt;8?x+1:0;
            int nextY = x&amp;lt;8?y:y+1;
            return nextField(nextX, nextY, matrix);
        }
        for(int i = 1; i&amp;lt;=9; i++) {
            matrix[y][x] = i;
            // check horizontal rule
            if (!isPotentialLegal(
                    matrix[y][0],matrix[y][1],matrix[y][2],
                    matrix[y][3],matrix[y][4],matrix[y][5],
                    matrix[y][6],matrix[y][7],matrix[y][8])) {
                continue;
            }
            int nextX = x&amp;lt;8?x+1:0;
            int nextY = x&amp;lt;8?y:y+1;
            return nextField(nextX, nextY, matrix);

        }
        return Optional.empty();
    }

    private static boolean isPotentialLegal(int... numbers) {
        final int[] counts = new int[10];
        for(int i = 0; i &amp;lt; numbers.length; i++) {
            counts[numbers[i]]++;
        }
        for(int i = 1; i &amp;lt; counts.length; i++) {
            if (counts[i]&amp;gt;1) return false;
        }
        return true;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;“isPotentialLegal” checks for distinct numbers by counting its occurences. It is called with all numbers of the current row. Zeros are “ignored”. If the rule is not satisfied, the next number is tried.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: Adding the “vertical rule”
&lt;/h1&gt;

&lt;p&gt;Now I add the rule for columns. To create a test, I use a solved sudoku puzzle and clear some cells:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final int[][] matrix = new int[][] {
            {7,9,0,3,5,4,6,0,8},
            {8,0,4,1,2,6,3,0,7},
            {3,0,1,9,8,7,5,2,4},
            //
            {9,4,5,6,0,8,1,7,2},
            {2,7,8,5,4,1,9,3,6},
            {6,1,3,0,9,2,8,4,5},
            //
            {4,2,9,8,1,5,7,6,3},
            {1,8,7,2,6,3,4,5,9},
            {5,3,6,4,7,9,2,0,0},
        };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and later check for the correct solution.&lt;br&gt;&lt;br&gt;
The implementation is straight forward next to the “horizonal rule”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (!isPotentialLegal(
                    matrix[y][0],matrix[y][1],matrix[y][2],
                    matrix[y][3],matrix[y][4],matrix[y][5],
                    matrix[y][6],matrix[y][7],matrix[y][8])
              ||
                !isPotentialLegal(
                    matrix[0][x],matrix[1][x],matrix[2][x],
                    matrix[3][x],matrix[4][x],matrix[5][x],
                    matrix[6][x],matrix[7][x],matrix[8][x])
                    ) {
                continue;
            }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4: Adding the “subquadrant rule”
&lt;/h1&gt;

&lt;p&gt;I wondered a bit about how to create a puzzle that would not be solvable without the subquadrant rule, but the original puzzle from Step 3 already did that. It has far more empty cells:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final int[][] matrix = new int[][] {
            {0,9,0, 0,0,0, 0,1,0},
            {8,0,4, 0,2,0, 3,0,7},
            {0,6,0, 9,0,7, 0,2,0},
            //
            {0,0,5, 0,3,0, 1,0,0},
            {0,7,0, 5,0,1, 0,3,0},
            {0,0,3, 0,9,0, 8,0,0},
            //
            {0,2,0, 8,0,5, 0,6,0},
            {1,0,7, 0,6,0, 4,0,9},
            {0,3,0, 0,0,0, 0,8,0},
        };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So here is the subquadrant rule. The key is to get the coordinates of the “subquadrant” right: integer division does the job, i.e. “(x/3)*3”. For example x=4 gets us “3” because it is the middle subquadrant starting at x=3. I use an extra method here because of the computation of the subquadrant start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private boolean isSubquadratPotentialLegal(int x, int y, int[][] matrix) {
        final int xx = (x/3)*3;
        final int yy = (y/3)*3;
        return isPotentialLegal(
            matrix[yy][xx],matrix[yy][xx+1],matrix[yy][xx+2],
            matrix[yy+1][xx],matrix[yy+1][xx+1],matrix[yy+1][xx+2],
            matrix[yy+2][xx],matrix[yy+2][xx+1],matrix[yy+2][xx+2]);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That did not made the test pass, though! It turned out I missed the backtracking-step, i.e. what happens when the recursion does not return a valid result – try next number (line 29):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public Optional&amp;lt;int[][]&amp;gt; nextField(int x, int y, int[][] matrix) {
        if (y==9 &amp;amp;&amp;amp; x == 0) {
            return Optional.of(matrix);
        }
        if (matrix[y][x]&amp;gt;0) {
            int nextX = x&amp;lt;8?x+1:0;
            int nextY = x&amp;lt;8?y:y+1;
            return nextField(nextX, nextY, matrix);
        }
        for(int i = 1; i&amp;lt;=9; i++) {
            matrix[y][x] = i;
            // check horizontal rule
            if (!(isPotentialLegal(
                    matrix[y][0],matrix[y][1],matrix[y][2],
                    matrix[y][3],matrix[y][4],matrix[y][5],
                    matrix[y][6],matrix[y][7],matrix[y][8])
              &amp;amp;&amp;amp;
              // check vertical rule
                isPotentialLegal(
                    matrix[0][x],matrix[1][x],matrix[2][x],
                    matrix[3][x],matrix[4][x],matrix[5][x],
                    matrix[6][x],matrix[7][x],matrix[8][x])
              &amp;amp;&amp;amp; isSubquadratPotentialLegal(x, y, matrix))) {
                continue;
            }
            int nextX = x&amp;lt;8?x+1:0;
            int nextY = x&amp;lt;8?y:y+1;
            final var result = nextField(nextX, nextY, matrix);
            if (result.isPresent()) return result;
        }
        matrix[y][x] = 0;
        return Optional.empty();
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moreover, line 31 “empties” the cell so that we leave it in the starting state.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;That’s it, I implemented a sudoku solver guided by tests. To answer my initial question: it’s fast. Well under one second!&lt;/strong&gt; I will write a follow-up discussion some optimizations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pBAEJ_Jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2023%252F11%252F19%252Fimplementing-a-simple-sudoku-solver%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dimplementing-a-simple-sudoku-solver%26action_name%3DImplementing%2Ba%2Bsimple%2Bsudoku%2Bsolver%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pBAEJ_Jt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2023%252F11%252F19%252Fimplementing-a-simple-sudoku-solver%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dimplementing-a-simple-sudoku-solver%26action_name%3DImplementing%2Ba%2Bsimple%2Bsudoku%2Bsolver%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" alt="" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>puzzle</category>
    </item>
    <item>
      <title>Dependency management: package.json and package-lock.json explained</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sat, 08 Apr 2023 19:30:46 +0000</pubDate>
      <link>https://forem.com/erikpischel/dependency-management-packagejson-and-package-lockjson-explained-26k4</link>
      <guid>https://forem.com/erikpischel/dependency-management-packagejson-and-package-lockjson-explained-26k4</guid>
      <description>&lt;p&gt;I had some confusion about &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;package-lock.json&lt;/code&gt; and what is used when. But now that I've been "enlightened", I'll record my new knowledge in this article.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga5ump0cg779lcbay142.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga5ump0cg779lcbay142.jpg" alt="symbolic image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  package.json and package-lock.json
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;package.json&lt;/code&gt; lists, among other things, the dependencies you need for your JavaScript project (if you use npm). You'd edit this file manually. In contrast &lt;code&gt;package-lock.json&lt;/code&gt; is generated by npm.&lt;/p&gt;

&lt;p&gt;Example &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "my-project",
  "version": "1.0.0",
  "dependencies": {
    "express": "^4.17.1",
    "lodash": "^4.17.20"
  },
  "devDependencies": {
    "nodemon": "^2.0.7"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Often, the versions listed in &lt;code&gt;package.json&lt;/code&gt; are given as ranges. npm uses &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;SemVer&lt;/a&gt;, meaning a version scheme in three parts like a.b.c where a,b and c are numbers (also called “major.minor.patch”). “&lt;code&gt;~a.b.c&lt;/code&gt;” means a and b are fixed and the last part can be c or any greater number: “&lt;code&gt;~4.17.1&lt;/code&gt;” means “4.17.x for x&amp;gt;=1”. “^a.b.c” means a is fixed and minor and patch version is variable: “&lt;code&gt;^4.17.20&lt;/code&gt;” means “4.x.y for either (x=17 and y&amp;gt;=20) or x&amp;gt;18”.&lt;/p&gt;

&lt;p&gt;In contrast, &lt;code&gt;package-lock.json&lt;/code&gt; contains the exact versions of the project's dependencies (and their transitive dependencies and so on). When &lt;code&gt;package-lock.json&lt;/code&gt; is generated or updated, the version range in &lt;code&gt;package.json&lt;/code&gt; is resolved to the latest “allowed” version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating and updating package-lock.json
&lt;/h2&gt;

&lt;p&gt;How do you create the lock file? “&lt;code&gt;npm install&lt;/code&gt;” will do it.&lt;/p&gt;

&lt;p&gt;How do you update the lock file? “&lt;code&gt;npm update&lt;/code&gt;” will do it, usually. Say &lt;code&gt;package.json&lt;/code&gt; states module A in version “&lt;code&gt;^3.4.5&lt;/code&gt;” and the existing &lt;code&gt;package-lock.json&lt;/code&gt; state module A in version “&lt;code&gt;3.4.20&lt;/code&gt;“. Then you run “&lt;code&gt;npm update A&lt;/code&gt;” or “&lt;code&gt;npm update&lt;/code&gt;” and when there is a version “&lt;code&gt;3.5.2&lt;/code&gt;” of A out there, npm will update the lockfile to version “&lt;code&gt;3.5.2&lt;/code&gt;” of module A.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;package.json&lt;/code&gt; and the lock file are out of sync (the version in &lt;code&gt;package-lock.json&lt;/code&gt; is out of the range specified in &lt;code&gt;package.json&lt;/code&gt;), “&lt;code&gt;npm install&lt;/code&gt;” will correct the &lt;code&gt;package-lock.json&lt;/code&gt; file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why committing the lock-file?
&lt;/h2&gt;

&lt;p&gt;The general advice is to commit &lt;code&gt;package-lock.json&lt;/code&gt; to your repository. That way, every developer will be using the same versions: the ones listed in the lock-file (using “&lt;code&gt;npm install&lt;/code&gt;“).&lt;/p&gt;

&lt;h2&gt;
  
  
  How to upgrade dependencies?
&lt;/h2&gt;

&lt;p&gt;“&lt;code&gt;npm outdated&lt;/code&gt;” shows outdated dependencies and “&lt;code&gt;npm update &amp;lt;pkg&amp;gt; --save&lt;/code&gt;” updates a package as well as &lt;code&gt;package.json&lt;/code&gt; and the lock file. Commit both files.&lt;/p&gt;

&lt;p&gt;Another way is to use tools like dependabot or renovate which check for new versions. If a new version of a module is detected, these tools will create a branch using the new version. CI pipelines are run and pull/merge requests are created or even merged automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI pipelines
&lt;/h2&gt;

&lt;p&gt;There is a special command for CI pipelines: “&lt;code&gt;npm ci&lt;/code&gt;“. It will fail if the lock file is missing or is out of sync with package.json. So the build will fail if “&lt;code&gt;npm install&lt;/code&gt;” would change the lock-file.&lt;/p&gt;

&lt;p&gt;“&lt;code&gt;npm ci&lt;/code&gt;” ensures that your build is always based on a consistent set of dependencies, which is important for reproducibility and stability. It also helps avoid problems that can arise from using different versions of the same package across different stages of the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pinning dependencies
&lt;/h2&gt;

&lt;p&gt;Pinning a dependency means using an exact version in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>npm</category>
    </item>
    <item>
      <title>3 things I learnt about GitLab CI</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Thu, 29 Dec 2022 20:50:20 +0000</pubDate>
      <link>https://forem.com/erikpischel/3-things-i-learnt-about-gitlab-ci-200b</link>
      <guid>https://forem.com/erikpischel/3-things-i-learnt-about-gitlab-ci-200b</guid>
      <description>&lt;p&gt;GitLab has a built-in CI system. A GitLab CI pipeline consists of a number of stages. In a stage, a number of jobs are executed in parallel. Jobs are executed as scripts within a docker container.&lt;/p&gt;

&lt;p&gt;In the last days I set out to expand my basic knowledge of GitLab CI pipelines (e.g. compiling a Java project with gradle) in order to write a pipelines that compiles, tests and deploys a project to a CloudFoundry instance. Here are 3 things I learnt about.&lt;/p&gt;

&lt;h1&gt;
  
  
  Reusing jobs with “extends”
&lt;/h1&gt;

&lt;p&gt;“extends” lets us reuse a job. &lt;strong&gt;It’s kind of “extract to method” refactoring&lt;/strong&gt; : suppose I write a job to publish to CloudFoundry. It consists of three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;install CloudFoundry CLI&lt;/li&gt;
&lt;li&gt;Login to CloudFoundry&lt;/li&gt;
&lt;li&gt;Publish app to CloudFoundry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A job that publishes an app to “dev” stage only differs in step 3 to a job that publishes the app to “test” stage. So we write a job that publishes an app to CloudFoundry based on some variables (e.g. “STAGE”)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.deploy-to-cf:
  script:
    - install cf cli
    - cf login -u "$CF_USER" -p "$CF_PASSWORD" -a "$CF_URL"
    - cf push -f manifest.yml --var STAGE=$STAGE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then our job “deploy-to-dev” just extends this job and redefines STAGE&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deploy-to-dev:
  extends: .deploy-to-cf
  variables:
    STAGE: "dev"
  when:
  - develop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can further “refactoring” our CI pipeline by “extracting” the install&amp;amp;login part because we have two CF foundations and therefore, two different values for “CF_USER” and “CF_PASSWORD”&lt;/p&gt;

&lt;h1&gt;
  
  
  Test results
&lt;/h1&gt;

&lt;p&gt;GitLab CI understands JUnit test result XML and we just need to provides it as artifact report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test:
  script:
    - gradlew test
  artifact:
    reports:
      junit: build/reports/**/TEST-*xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the test results in the pipeline and in the merge request screen.&lt;/p&gt;

&lt;h1&gt;
  
  
  Speed up caches
&lt;/h1&gt;

&lt;p&gt;Our pipeline uses the cache to avoid downloading gradle (our build tool) and all dependencies everytime a job builds or tests the code. But it is painfully slow, especially collecting the files and pushing the cache.&lt;/p&gt;

&lt;p&gt;In my case it takes several minutes (!) to collect 3000+ files in .gradle dir. Things sped up significantly when adding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variables:
  FF_USE_FASTZIP: "true"
  CACHE_COMPRESSION_LEVEL: "fast"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the &lt;a href="https://archives.docs.gitlab.com/13.9/ee/ci/runners/#artifact-and-cache-settings" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.epischel.de%2Fanalytics%2Fpiwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2022%252F12%252F29%252F3-things-i-learnt-about-gitlab-ci%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253D3-things-i-learnt-about-gitlab-ci%26action_name%3D3%2Bthings%2BI%2Blearnt%2Babout%2BGitLab%2BCI%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.epischel.de%2Fanalytics%2Fpiwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2022%252F12%252F29%252F3-things-i-learnt-about-gitlab-ci%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253D3-things-i-learnt-about-gitlab-ci%26action_name%3D3%2Bthings%2BI%2Blearnt%2Babout%2BGitLab%2BCI%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" width="1" height="1"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>continuousdeployment</category>
      <category>ci</category>
      <category>gitlab</category>
    </item>
    <item>
      <title>No password required: authenticate using Github access tokens</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Mon, 12 Jul 2021 19:59:43 +0000</pubDate>
      <link>https://forem.com/erikpischel/no-password-required-authenticate-using-github-access-tokens-4ik9</link>
      <guid>https://forem.com/erikpischel/no-password-required-authenticate-using-github-access-tokens-4ik9</guid>
      <description>&lt;p&gt;You are using Github as remote git repository? This article explains how to use an access token to authenticate yourself instead of username+password.&lt;/p&gt;

&lt;h1&gt;
  
  
  Create an access token
&lt;/h1&gt;

&lt;p&gt;On Github.com, navigate to the setting menu of your Github profile. From there, choose “Developer Settings” and then “Personal Account Tokens”.&lt;/p&gt;

&lt;p&gt;Here you are able to create a personal account token:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://on-sw-integration.epischel.de/wp-content/uploads/2021/07/screenshot-github-newtoken.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EYKUlt-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://on-sw-integration.epischel.de/wp-content/uploads/2021/07/screenshot-github-newtoken-300x218.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;create new token&lt;/p&gt;

&lt;p&gt;Select scope “repo”.&lt;/p&gt;

&lt;p&gt;The token you created is presented to you. Save it to you credentials store (like KeePass).&lt;/p&gt;

&lt;h1&gt;
  
  
  Use the token
&lt;/h1&gt;

&lt;p&gt;The token is part of the remote url of the repository. The URL has this form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://userid:token@github.com/projectid/repo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;e.g. for a repo of mine and suppose the token is “token1234567890”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://epischel:token1234567890@github.com/epischel/gensources.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you are using the token in the remote URL you won’t be prompted for your password.&lt;/p&gt;

&lt;p&gt;Good luck with your repo on Github!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--38m0vov3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2021%252F07%252F12%252Fauthenticate-using-github-access-tokens%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dauthenticate-using-github-access-tokens%26action_name%3DAuthenticate%2Busing%2BGithub%2BAccess%2BTokens%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--38m0vov3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2021%252F07%252F12%252Fauthenticate-using-github-access-tokens%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dauthenticate-using-github-access-tokens%26action_name%3DAuthenticate%2Busing%2BGithub%2BAccess%2BTokens%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Tracking dependency updates</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sun, 03 Jan 2021 08:09:32 +0000</pubDate>
      <link>https://forem.com/erikpischel/tracking-dependency-updates-5djg</link>
      <guid>https://forem.com/erikpischel/tracking-dependency-updates-5djg</guid>
      <description>&lt;p&gt;Many software projects use 3rd party libraries aka “dependencies”. You often want to use the most recent version of these dependencies but how do you know when a new release of a dependency is published? The more dependencies your project have the more tiresome a manual approach to “tracking dependency updates” is.&lt;/p&gt;

&lt;p&gt;In this post I explore some solutions that tracks dependency updates for you. I cover broad solutions (libraries.io and dependabot) and Java-only solutions (“artifact listener” and a Gradle/Maven plugin).&lt;/p&gt;

&lt;h2&gt;
  
  
  Why update?
&lt;/h2&gt;

&lt;p&gt;But why do we want to update dependencies at all?&lt;/p&gt;

&lt;p&gt;A new version of a dependency&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;may fix bugs that affects your project&lt;/li&gt;
&lt;li&gt;may introduce new features that you could use&lt;/li&gt;
&lt;li&gt;may fix a security issue that affects your project&lt;/li&gt;
&lt;li&gt;may have other optimizations to the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course there is a risk as well: a new version may introduce a bug that affects your project. Plus, there might be API changes that require changes in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracking solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Libraries.io
&lt;/h3&gt;

&lt;p&gt;With their own words&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://libraries.io"&gt;Libraries.io&lt;/a&gt; can automatically keep track of all of the packages that your repositories depend upon across many different package managers.&lt;/p&gt;

&lt;p&gt;Once synced, Libraries.io will email you about new versions of your dependencies, if you add or remove a new dependency it will change the notifications settings for that package as soon as you push to your repositories.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repositories on Github, Gitlab and Bitbucket are supported. Plus, you can subscribe to dependencies manually, ie without a repository on any of these platforms.&lt;/p&gt;

&lt;p&gt;Beside email notifications you can also subscribe to an RSS feed of your dependency updates.&lt;/p&gt;

&lt;p&gt;Libraries.io is an open source project.&lt;/p&gt;

&lt;h3&gt;
  
  
  artifact listener
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.artifact-listener.org/"&gt;Artifact Listener&lt;/a&gt; is a small service and only available for Java / Maven Central. You can search for libraries and “follow” them. Alternatively you can upload a POM and then choose which dendencies to follow. Updates of libraries you follow are emailed to you.&lt;/p&gt;

&lt;p&gt;You can provide additional email adresses to notify, e.g, email addresses of other team members. This is a small but lovely feature for me.&lt;/p&gt;

&lt;p&gt;The service is an open source project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependabot
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.dependabot.com/"&gt;Dependabot&lt;/a&gt; checks the “dependency files” (where your dependencies are definied) in your Github repos for updates. If there is an update it creates a PR for it. The PR may contain links, release notes, a list of commits etc.&lt;/p&gt;

&lt;p&gt;So this service not only notifies you about an update but even creates a PR that applies it. You just have to merge it (at least if your project is on Github).&lt;/p&gt;

&lt;p&gt;Dependabout has been aquired by Github.com and is free of charge.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gradle plugin
&lt;/h3&gt;

&lt;p&gt;If you are using Gradle (a Java build system) to declare dependencies and build your project you can use the &lt;a href="https://github.com/ben-manes/gradle-versions-plugin"&gt;Gradle versions plugin&lt;/a&gt; to detect dependency updates and report them. It is easy to use. You just need to execute it on a regular basis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Maven plugin
&lt;/h3&gt;

&lt;p&gt;Of course, there is a &lt;a href="https://www.mojohaus.org/versions-maven-plugin/index.html"&gt;similar plugin&lt;/a&gt; for Maven (another Java build system).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E8VR206V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2021%252F01%252F03%252Ftracking-dependency-updates%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dtracking-dependency-updates%26action_name%3DTracking%2Bdependency%2Bupdates%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E8VR206V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2021%252F01%252F03%252Ftracking-dependency-updates%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dtracking-dependency-updates%26action_name%3DTracking%2Bdependency%2Bupdates%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>webdev</category>
      <category>java</category>
    </item>
    <item>
      <title>Working Software</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Fri, 04 Dec 2020 20:56:35 +0000</pubDate>
      <link>https://forem.com/erikpischel/working-software-4h0i</link>
      <guid>https://forem.com/erikpischel/working-software-4h0i</guid>
      <description>&lt;p&gt;Ron Jeffries published a wonderful post titled “&lt;a href="https://ronjeffries.com/articles/020-01ff/working-software/"&gt;working software&lt;/a&gt;“. He quotes the agile manifesto “working software is the primary measure of progress”.&lt;/p&gt;

&lt;p&gt;Now, he explains that what exactly “working software” means depends (as always). But in general,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Working software is real. It works. It can be tested. It can be verified. Questions about whether it does X are readily answered with “Yes” or “No”. The less ambiguity there is in our answers—our true answers—the closer to “working software” we are.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And he shares his opinion on “best development style”:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The best development style we know today, whether working solo, in pairs, or in a mob, is to pick a very small thing that the system doesn’t as yet do, verify that it doesn’t do it, then make it do that thing, verifying again, and keeping the code at or above our standard of internal quality.&lt;/p&gt;

&lt;p&gt;How small should that thing be? Tiny. Smaller than that. No, smaller still.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I repeat that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;pick a very small thing that the system doesn’t do yet&lt;/li&gt;
&lt;li&gt;verify it doesn’t do it (the “red” step in the TDD cycle)&lt;/li&gt;
&lt;li&gt;make it do that thing&lt;/li&gt;
&lt;li&gt;verify it does it (the “green” step in TDD)&lt;/li&gt;
&lt;li&gt;keeping the code at or above our quality standard (the “refactor” step in TDD).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I really like that. It’s not always that easy. But more often than not.&lt;/p&gt;

&lt;p&gt;I know of TDD but I need to get better at remembering this (I’ll put that in my Anki deck) – including the &lt;em&gt;very small&lt;/em&gt; part – and then practice it.&lt;/p&gt;

</description>
      <category>agile</category>
      <category>programming</category>
      <category>tdd</category>
    </item>
    <item>
      <title>How a 2 GB CLOB crashed our app</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sat, 29 Aug 2020 17:28:22 +0000</pubDate>
      <link>https://forem.com/erikpischel/how-a-2-gb-clob-crashed-our-app-350b</link>
      <guid>https://forem.com/erikpischel/how-a-2-gb-clob-crashed-our-app-350b</guid>
      <description>&lt;p&gt;Our latest production issue: one morning our app kept crashing. Restart. Crash after some minutes. Out of memory.  &lt;/p&gt;

&lt;p&gt;It turned out to be a CLOB that was almost 2 GB big and got read when a user triggered a certain action. The 2 GB CLOB ended up in an almost 4 GB big &lt;code&gt;char[]&lt;/code&gt; (because char is 16 bit in Java) and this was too much even for 8 GB heap space.&lt;/p&gt;

&lt;p&gt;Of course that CLOB was not supposed to be that big!&lt;/p&gt;

&lt;p&gt;It took some time to identify the root cause.&lt;/p&gt;

</description>
      <category>production</category>
      <category>java</category>
    </item>
    <item>
      <title>WLS “Context propagation” forced to restart our app server</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sat, 29 Aug 2020 17:24:44 +0000</pubDate>
      <link>https://forem.com/erikpischel/wls-context-propagation-forced-to-restart-our-app-server-1mlo</link>
      <guid>https://forem.com/erikpischel/wls-context-propagation-forced-to-restart-our-app-server-1mlo</guid>
      <description>&lt;p&gt;Our app runs on a Weblogic server (WLS) and talks to another WLS-hosted app via a SOAP-Webservice.  &lt;/p&gt;

&lt;p&gt;When the other app was patched to a new version, some WS-requests failed indicating that the webservice in the other app wanted to JNDI-lookup the previous version of something.  &lt;/p&gt;

&lt;p&gt;After we restarted our app everything worked fine. But still you don’t want to restart a client when the server was upgraded. Moreover, a spring boot based client did not have these problems.  &lt;/p&gt;

&lt;p&gt;It turned out that WLS uses a feature called “Context Propagation” that inserts an additional SOAP-Header into the request as well as the response. This header contains a serialized object. It indicated that our app transmits the version of the other app and apperantly the other app somehow uses that information in the JNDI lookup.  &lt;/p&gt;

&lt;p&gt;How does our app knows about the version number of the other app? Probably because the other apps sends that info in the response. This explains why it worked after we restarted our app: at first it hadn’t that information at all and when it got it, it was about the new version.  &lt;/p&gt;

&lt;p&gt;What I still can’t explain is that some request were successful before the restart.  &lt;/p&gt;

&lt;p&gt;The solution is to disable “context propagation” by using a system parameter:&lt;br&gt;&lt;br&gt;
weblogic.wsee.workarea.skipWorkAreaHeader=true&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0x6_oIRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2020%252F08%252F29%252Fwls-context-propagation-forced-to-restart-our-app-server%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dwls-context-propagation-forced-to-restart-our-app-server%26action_name%3DWLS%2B%2526%25238220%253BContext%2Bpropagation%2526%25238221%253B%2Bforced%2Bto%2Brestart%2Bour%2Bapp%2Bserver%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0x6_oIRu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2020%252F08%252F29%252Fwls-context-propagation-forced-to-restart-our-app-server%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dwls-context-propagation-forced-to-restart-our-app-server%26action_name%3DWLS%2B%2526%25238220%253BContext%2Bpropagation%2526%25238221%253B%2Bforced%2Bto%2Brestart%2Bour%2Bapp%2Bserver%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>production</category>
      <category>java</category>
      <category>weblogic</category>
    </item>
    <item>
      <title>How to split a git repository</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Sat, 25 Jan 2020 20:58:02 +0000</pubDate>
      <link>https://forem.com/erikpischel/how-to-split-a-git-repository-2go8</link>
      <guid>https://forem.com/erikpischel/how-to-split-a-git-repository-2go8</guid>
      <description>&lt;p&gt;Say your git repo consists of a subdirectory “app” and a subdirectory “database” (or “frontend” and “backend” or “team-a” and “team-b”) and you realize each directories content should be in its own repository. Here is how to split the repo.&lt;/p&gt;

&lt;p&gt;To create a repo that consists of the content of the “database” dir and its history, execute&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git filter-branch --prune-empty --tag-name-filter cat --subdirectory-filter database -- --all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and then push it to a new remote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote rename origin old-origin
git remote add origin &amp;lt;new-remote&amp;gt;
git push -u origin --all
git push -u origin --tags
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is what Gitlab states on a newly created project page. However in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -u origin --all
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;“-all” should be replaced with “–mirror” because “-all” pushes all local branches only so you would need to checkout all branches you want to keep. “–mirror” pushes remote branches, too.&lt;/p&gt;

&lt;p&gt;In the same fashion apply “filter-branches” to the “app” directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does it work?&lt;/strong&gt; &lt;a href="https://git-scm.com/docs/git-filter-branch"&gt;"git filter-branches"&lt;/a&gt; rewrites git revision history of the mentioned branches by applying filters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The mentioned branches states "--all" so filters are applied to all branches of the repo (you need "--" before "--all" because otherwise "--all" would get interpreted as a revision) &lt;/li&gt;
&lt;li&gt;"--subdirectory-filter" means "only look at the history which touches this directory" and also make that directory the root of the repo. &lt;/li&gt;
&lt;li&gt;"--prune-empty" removes any empty commits that may get created&lt;/li&gt;
&lt;li&gt;Git itself recommends using "--tag-name-filter cat" when not stated, it simply updates tags (apparently "--all" does not include tags).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Java method references recap</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Fri, 18 Oct 2019 20:10:46 +0000</pubDate>
      <link>https://forem.com/erikpischel/java-method-references-recap-4obi</link>
      <guid>https://forem.com/erikpischel/java-method-references-recap-4obi</guid>
      <description>&lt;p&gt;In the last post I reviewed Java lambda expressions. &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/erikpischel" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NKnYqecW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--w7SlrOxK--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/55449/36a91856-2126-4965-b85a-92ccd84dfff8.jpg" alt="erikpischel image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/erikpischel/java-lambda-expressions-recap-180b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Java lambda expressions recap&lt;/h2&gt;
      &lt;h3&gt;Erik Pischel ・ Oct 16 '19 ・ 2 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#java&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#lambdaexpressions&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#recap&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
 They represent a concise syntax to implement functional interfaces.

&lt;p&gt;Enter &lt;strong&gt;Java method references&lt;/strong&gt;. They represent a concise syntax to implement functional interface &lt;strong&gt;using existing methods&lt;/strong&gt;. Like with lambda expressions, referenced methods are not allowed to throw checked exceptions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Syntax
&lt;/h2&gt;

&lt;p&gt;It’s simply “class-or-instance name” “::” “method name”, like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;string2Int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;Integer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Types of method references
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Reference to a static method
&lt;/h3&gt;

&lt;p&gt;Static methods are referenced using the class name like in the example above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference to an instance method of a particular object
&lt;/h3&gt;

&lt;p&gt;Methods of a particular object are referenced using the variable name of that object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;aMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;aMap:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// call it&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getRef&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Reference to an instance method of an arbitary object of a particular type
&lt;/h3&gt;

&lt;p&gt;Instead of using an already existing object you can just state the class and a non-static method. Then the instance is an additional parameter. In the following example toURI is a method with no arguments that returns a String. The function of this method reference takes a File (the object) and returns a String:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;file2Uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;File:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;toURI&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Reference to a constructor
&lt;/h3&gt;

&lt;p&gt;Constructors are references using its type and “new”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StringBuffer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bufferFromString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nl"&gt;StringBuffer:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here the constructor of StringBuffer with String parameter is referenced. Return type is the type of the constructor, parameters of the function are the parameters of the constructors.&lt;/p&gt;

</description>
      <category>java</category>
      <category>recap</category>
    </item>
    <item>
      <title>Sprint Goal in Scrum</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Thu, 17 Oct 2019 08:05:14 +0000</pubDate>
      <link>https://forem.com/erikpischel/sprint-goal-in-scrum-43nh</link>
      <guid>https://forem.com/erikpischel/sprint-goal-in-scrum-43nh</guid>
      <description>&lt;p&gt;A reading recommendation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.scrum.org/resources/blog/myth-having-sprint-goal-optional-scrum"&gt;Myth: Having A Sprint Goal Is Optional In Scrum&lt;/a&gt; &lt;em&gt;(&lt;span&gt;Scrum.org&lt;/span&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;Sprint Goals are one of the more elusive parts of the Scrum Framework. Most teams know they are important, but few use them - for a variety of reasons. In this post, Barry Overeem and I bust the myth that Sprint Goals are optional in Scrum. And we make an effort to show what makes them so vital in the face of complex work. And more importantly, what you can do to start working with Sprint Goals from now on.&lt;/blockquote&gt;

&lt;p&gt;I really like this article because I am in a Scrum team where everyone works in his/her niche area. So far we haven’t used Sprint goals. I agree with the observation in the “What happens without Sprint Goals” – section, especially:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Without Sprint Goals, each Sprint implicitly has the same purpose: complete all the work.  &lt;strong&gt;This makes all Sprints the same&lt;/strong&gt; , and can make people (rightfully) complain that they are artificial;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So if you’re in a Scrum team that doesn’t use sprint goals, this is definitely a must read.&lt;/p&gt;

</description>
      <category>agiledevelopment</category>
      <category>agile</category>
      <category>scrum</category>
    </item>
    <item>
      <title>Agile back to basics with Robert C. Martin</title>
      <dc:creator>Erik Pischel</dc:creator>
      <pubDate>Wed, 16 Oct 2019 10:09:28 +0000</pubDate>
      <link>https://forem.com/erikpischel/agile-back-to-basics-with-robert-c-martin-6bi</link>
      <guid>https://forem.com/erikpischel/agile-back-to-basics-with-robert-c-martin-6bi</guid>
      <description>&lt;p&gt;&lt;a href="https://cynicaldeveloper.com/podcast/125/"&gt;Episode 125 - Agile back to basics&lt;/a&gt; &lt;em&gt;(&lt;span&gt;The Cynical Developer Podcast&lt;/span&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;In this episode we talk to Robert C. Martin, many of you might know him as Uncle Bob, and we're here to talk Agile and taking it back to basics.&lt;/blockquote&gt;

&lt;p&gt;A great podcast episode with Robert C. Martin on “Agile – back to the basics”. So what are, in the time of Scrum, LeSS, SaFE etc., the basics of Agile?&lt;/p&gt;

&lt;p&gt;Apparently, “Uncle Bob” has a new book in the works, “Clean Agile” (duh!), covering this subject.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t_htC6yb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2019%252F10%252F16%252Fpodcast-agile-basics%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dpodcast-agile-basics%26action_name%3DAgile%2Bback%2Bto%2Bbasics%2Bwith%2BRobert%2BC.%2BMartin%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t_htC6yb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.epischel.de/analytics/piwik.php%3Fidsite%3D3%26rec%3D1%26url%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252F2019%252F10%252F16%252Fpodcast-agile-basics%252F%253Fpk_campaign%253Dfeed%2526pk_kwd%253Dpodcast-agile-basics%26action_name%3DAgile%2Bback%2Bto%2Bbasics%2Bwith%2BRobert%2BC.%2BMartin%26urlref%3Dhttps%253A%252F%252Fon-sw-integration.epischel.de%252Ffeed%252F" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agiledevelopment</category>
      <category>agile</category>
      <category>podcast</category>
    </item>
  </channel>
</rss>
