<?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: Yann Rabiller</title>
    <description>The latest articles on Forem by Yann Rabiller (@einenlum).</description>
    <link>https://forem.com/einenlum</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%2F3176%2Fcff5dbd3-f493-4af5-afff-482955180a14.jpg</url>
      <title>Forem: Yann Rabiller</title>
      <link>https://forem.com/einenlum</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/einenlum"/>
    <language>en</language>
    <item>
      <title>Tailwind Alchemist: find all tailwind colors in your codebase</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 04 Feb 2026 15:29:15 +0000</pubDate>
      <link>https://forem.com/einenlum/tailwind-alchemist-find-all-tailwind-colors-in-your-codebase-5f1o</link>
      <guid>https://forem.com/einenlum/tailwind-alchemist-find-all-tailwind-colors-in-your-codebase-5f1o</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was initially published on my &lt;a href="https://www.einenlum.com/articles/tailwind-alchemist-find-all-tailwind-colors-in-your-codebase/" rel="noopener noreferrer"&gt;blog&lt;/a&gt; — sharing here for the Dev.to community.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I love Tailwind. For a long time, I was afraid of CSS and almost didn't want to understand it. Tailwind made me feel like it's not such a big deal after all.&lt;/p&gt;

&lt;p&gt;Some people say that they lost their CSS knowledge because of Tailwind, but for me it's the opposite. I'm now curious about it and it feels great!&lt;/p&gt;

&lt;p&gt;At some point though, I realized something was quite annoying. When using Tailwind, you put the color (or bg color) directly on the element, which is great to understand quickly how the component looks like, but if you decide to change the theme later, you have to go through all your codebase and change the color names one by one.&lt;/p&gt;

&lt;p&gt;I tried to create a design system to avoid this, but I was not that great at finding names and it always ended up in a big mess.&lt;/p&gt;

&lt;p&gt;I later discovered &lt;a href="https://daisyui.com/" rel="noopener noreferrer"&gt;DaisyUI&lt;/a&gt;, which provides a theme system on top of Tailwind. Instead of using color names like &lt;code&gt;bg-blue-500&lt;/code&gt;, you can use semantic names like &lt;code&gt;bg-primary&lt;/code&gt; and then define what &lt;code&gt;primary&lt;/code&gt; means in your theme.&lt;/p&gt;

&lt;p&gt;Changing the theme is then super easy, you just change the color values in your theme definition.&lt;/p&gt;

&lt;p&gt;There's one problem though: when you start with some templates (like &lt;a href="https://fluxui.dev/" rel="noopener noreferrer"&gt;Flux UI&lt;/a&gt; or &lt;a href="https://ui.shadcn.com/" rel="noopener noreferrer"&gt;Shadcn&lt;/a&gt; which are used by the Laravel starter kits), you have a lot of hardcoded Tailwind color names in your codebase. Adding DaisyUI later means you have to go through all your codebase and replace the color names with semantic names.&lt;/p&gt;

&lt;p&gt;I could not find a simple tool to do this, so I built one: &lt;a href="https://github.com/einenlum/tailwind-alchemist" rel="noopener noreferrer"&gt;Tailwind Alchemist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's made in Typescript and works as a CLI tool. You just give it the path to your codebase, and it finds all default Tailwind color names that are still present in your files.&lt;/p&gt;

&lt;p&gt;Here is how you can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx tw-alchemist scan &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'resources/js/**'&lt;/span&gt;      

Found 28 Tailwind colors:

amber-400
black
blue-100
blue-200
blue-700
blue-800
green-500
green-600
neutral-100
neutral-200
neutral-300
neutral-400
neutral-500
neutral-600
neutral-700
neutral-800
neutral-900
orange-300
red-100
red-200
red-50
red-500
red-600
red-700
violet-500
white
yellow-500
zinc-900
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to know which files contain which colors, you can add the &lt;code&gt;-v&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx tw-alchemist scan &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'resources/js/**'&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt;

Found 28 Tailwind colors:

Color: violet-500 &lt;span class="o"&gt;(&lt;/span&gt;found &lt;span class="k"&gt;in &lt;/span&gt;3 files&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppHeader.vue
  - resources/js/components/AppLogo.vue
  - resources/js/components/MobileHeader.vue

Color: neutral-500 &lt;span class="o"&gt;(&lt;/span&gt;found &lt;span class="k"&gt;in &lt;/span&gt;5 files&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppHeader.vue
  - resources/js/components/AppearanceTabs.vue
  - resources/js/components/TextLink.vue
  - resources/js/pages/auth/TwoFactorChallenge.vue
  - resources/js/pages/settings/Profile.vue

Color: neutral-100 &lt;span class="o"&gt;(&lt;/span&gt;found &lt;span class="k"&gt;in &lt;/span&gt;3 files&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppearanceTabs.vue
  - resources/js/components/NavFooter.vue
  - resources/js/components/PlaceholderPattern.vue

Color: neutral-800 &lt;span class="o"&gt;(&lt;/span&gt;found &lt;span class="k"&gt;in &lt;/span&gt;2 files&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppearanceTabs.vue
  - resources/js/components/NavFooter.vue

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

&lt;/div&gt;



&lt;p&gt;If you want to know which lines (and which class utilities) contain the colors, you can use extra verbosity with the &lt;code&gt;-vv&lt;/code&gt; flag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;npx tw-alchemist scan &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'resources/js/**'&lt;/span&gt; &lt;span class="nt"&gt;-vv&lt;/span&gt;

Found 28 Tailwind colors:

Color: violet-500 &lt;span class="o"&gt;(&lt;/span&gt;3 occurrences&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppHeader.vue
    - Line 106: text-violet-500
  - resources/js/components/AppLogo.vue
    - Line 10: text-violet-500
  - resources/js/components/MobileHeader.vue
    - Line 28: text-violet-500

Color: neutral-500 &lt;span class="o"&gt;(&lt;/span&gt;6 occurrences&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppHeader.vue
    - Line 233: text-neutral-500
  - resources/js/components/AppearanceTabs.vue
    - Line 33: text-neutral-500
  - resources/js/components/TextLink.vue
    - Line 21: dark:decoration-neutral-500
  - resources/js/pages/auth/TwoFactorChallenge.vue
    - Line 100: dark:decoration-neutral-500
    - Line 132: dark:decoration-neutral-500
  - resources/js/pages/settings/Profile.vue
    - Line 244: dark:decoration-neutral-500

Color: neutral-100 &lt;span class="o"&gt;(&lt;/span&gt;4 occurrences&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppearanceTabs.vue
    - Line 23: bg-neutral-100
    - Line 32: dark:text-neutral-100
  - resources/js/components/NavFooter.vue
    - Line 28: dark:hover:text-neutral-100
  - resources/js/components/PlaceholderPattern.vue
    - Line 11: dark:stroke-neutral-100

Color: neutral-800 &lt;span class="o"&gt;(&lt;/span&gt;2 occurrences&lt;span class="o"&gt;)&lt;/span&gt;
  - resources/js/components/AppearanceTabs.vue
    - Line 23: dark:bg-neutral-800
  - resources/js/components/NavFooter.vue
    - Line 28: hover:text-neutral-800

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

&lt;/div&gt;



&lt;p&gt;It only supports Tailwind v4. It's also on &lt;a href="https://context7.com/" rel="noopener noreferrer"&gt;Context7&lt;/a&gt; so you can ask your LLM (with the right MPC) to use it when refactoring your codebase.&lt;/p&gt;

&lt;p&gt;I hope it can be useful to you. If you like it, feel free to give it a star &lt;a href="https://github.com/einenlum/tailwind-alchemist" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt; ⭐️&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>css</category>
      <category>design</category>
      <category>daisyui</category>
    </item>
    <item>
      <title>A free CI (using Docker-Compose) for your Gitlab repositories?</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 03 Oct 2018 23:18:07 +0000</pubDate>
      <link>https://forem.com/einenlum/a-free-ci-using-docker-compose-for-your-gitlab-repositories-6po</link>
      <guid>https://forem.com/einenlum/a-free-ci-using-docker-compose-for-your-gitlab-repositories-6po</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally posted on my &lt;a href="https://www.einenlum.com/articles/free-ci-gitlab" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you're like me, you use Github for public repositories and for private repositories owned by organizations, but for your own private repositories, you use Gitlab. Indeed, Gitlab offers free unlimited private repositories and does the job.&lt;/p&gt;

&lt;p&gt;After having pushed a lot of commits, you decide that it could be really nice to automate your tests every time a Merge Request (yes, Merge Request. We're talking Gitlab language here) is created.&lt;/p&gt;

&lt;p&gt;Then you think that you could use CircleCI as you do for your Github repositories, &lt;a href="https://dev.to/einenlum/testing-your-app-with-docker-compose-on-circleci-1ll"&gt;especially since you know how to use docker-compose on it&lt;/a&gt;. You log into your CircleCI account, go to the integration page, and realize &lt;a href="https://circleci.com/integrations/" rel="noopener noreferrer"&gt;Gitlab integration is missing&lt;/a&gt;. Github is there, as well as Bitbucket, but no Gitlab in the area. Shit. &lt;a href="https://circleci.com/ideas/?idea=CCI-I-248" rel="noopener noreferrer"&gt;You can still upvote the idea of a Gitlab integration on CircleCI's website&lt;/a&gt;, but until they decide to change things, you're stuck.&lt;/p&gt;

&lt;p&gt;You decide to list all the free CI services that can work with Gitlab and match your expectations. And then you realize that Gitlab offers a CI service. &lt;a href="https://about.gitlab.com/features/gitlab-ci-cd/" rel="noopener noreferrer"&gt;After having read all the not clear at all advertised features on the website&lt;/a&gt; (&lt;strong&gt;to Gitlab’s commercials: you have a nice product, we just don’t realize how cool is your offer since everything is so fuzzy on your website. It’s a shame&lt;/strong&gt;) you start to think that maybe they offer a free CI even for people using free private repositories on the Community Edition. It seems it is limited to 2000 build minutes per month, which is frankly a very generous deal. Our question today is more precise: is it possible to use docker-compose to build the whole stack and run your tests in the CI? Yup.&lt;/p&gt;

&lt;p&gt;First, the (very bad…) documentation says you need to enable some shared runners, but in my case it was already done by default, so I guess you don’t need to do it either. Next.&lt;/p&gt;

&lt;p&gt;Now we just need to create a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file in the root directory of our project. &lt;a href="https://docs.gitlab.com/ce/ci/yaml/" rel="noopener noreferrer"&gt;This is quite documented for the general use&lt;/a&gt;, but there is no track of docker-compose in the documentation. It seems we just need to install it as a python package (&lt;a href="https://stackoverflow.com/questions/39868369/run-docker-compose-build-in-gitlab-ci-yml/42697808#42697808" rel="noopener noreferrer"&gt;thank you Stack Overflow!&lt;/a&gt;) and then we can use it. We also need to use some obscure image:docker and docker:dind services. Well, if it works, why not.&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker:dind&lt;/span&gt;

&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add --no-cache py-pip&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install docker-compose&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose up -d&lt;/span&gt;
  &lt;span class="c1"&gt;# here we can install our dependencies (composer, yarn…)&lt;/span&gt;

&lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# launch our tests&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php phpspec run --format pretty&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php phpunit&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php behat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quite easy actually. I just had some issue (that I don’t have locally or on CircleCI) with the interactive TTY while executing &lt;code&gt;docker-compose exec&lt;/code&gt;. Maybe because the version used by pip is &lt;a href="https://github.com/docker/compose/issues/5696#issue-299103105" rel="noopener noreferrer"&gt;the one adding a regression&lt;/a&gt;? I dunno. Anyway, you can fix the issue by adding a &lt;code&gt;-T&lt;/code&gt; tag to your commands.&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;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker:dind&lt;/span&gt;

&lt;span class="na"&gt;before_script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apk add --no-cache py-pip&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip install docker-compose&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose up -d&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec -T php composer install&lt;/span&gt;

&lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec -T php phpspec run --format pretty&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec -T php phpunit&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec -T php behat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should do the trick. Hope it helped. Happy testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update&lt;/em&gt;&lt;/strong&gt;: Actually, maybe I spoke too fast…&lt;br&gt;
&lt;strong&gt;I have an issue with the network. Containers cannot communicate with each others… Maybe I can play with the network options (network_mode?).&lt;br&gt;
If a docker expert is here, I would love some help :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image by &lt;a href="https://www.flickr.com/photos/paradasos/7234825030/" rel="noopener noreferrer"&gt;Paradasos&lt;/a&gt; (CC by/nc)&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>gitlab</category>
      <category>testing</category>
      <category>dockercompose</category>
    </item>
    <item>
      <title>Testing your app with docker-compose on CircleCI</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Tue, 02 Oct 2018 14:20:38 +0000</pubDate>
      <link>https://forem.com/einenlum/testing-your-app-with-docker-compose-on-circleci-1ll</link>
      <guid>https://forem.com/einenlum/testing-your-app-with-docker-compose-on-circleci-1ll</guid>
      <description>&lt;p&gt;&lt;em&gt;This article was originally posted on &lt;a href="https://www.einenlum.com/articles/docker-compose-circle-ci" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a dev, you use docker as a dev environment. You're quite happy that you finally ended mastering it (or at least make it work \o/). Since you're a great developer, you know the importance of automated testing, and you wrote a bunch of specs or features to test. You made everything work locally thanks to a few docker-compose commands. Maybe you're thinking now that it could be awesome to even automate the process of launching those tests, by delegating this process to a CI, that will listen to your Github events, and send you back a green or red dot on your Pull Request's page.&lt;/p&gt;

&lt;p&gt;Since you used CircleCI a few years ago, since they claim it's easy to use with docker and since they provide a free plan, you think you're gonna make it standing on your head. Well, let me tell you that it can be quite a pain in the a** if you don't have the right instructions, and the documentation is quite awful when it comes to using it with docker-compose. Fortunately, it can be very easy when you get the right options to use in the config.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's dive into it!
&lt;/h2&gt;

&lt;p&gt;After having created your CircleCI account and connected it to your repository, you will have a sample config file given by CircleCI. It may look like this (hum...):&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/mern-starter&lt;/span&gt;
    &lt;span class="c1"&gt;# The primary container is an instance of the first image listed. The job's commands run in this container.&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&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;circleci/node:4.8.2-jessie&lt;/span&gt;
    &lt;span class="c1"&gt;# The secondary container is an instance of the second listed image which is run in a common network where ports exposed on the primary container are available on localhost.&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;mongo:3.4.4-jessie&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update npm&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sudo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;npm&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;install&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-g&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;npm@latest'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;restore_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-cache-{{ checksum "package.json" }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install npm wee&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;save_cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dependency-cache-{{ checksum "package.json" }}&lt;/span&gt;
          &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;node_modules&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&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;circleci/node:4.8.2-jessie&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;mongo:3.4.4-jessie&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate code coverage&lt;/span&gt;
          &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./node_modules/.bin/nyc&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;report&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;--reporter=text-lcov'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test-results.xml&lt;/span&gt;
          &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tests&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;
          &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage&lt;/span&gt;

&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;build_and_test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well, that's quite intimidating. At least there is the &lt;code&gt;docker&lt;/code&gt; keyword, so you think you're going in the right direction. Let me tell me you're wrong.&lt;/p&gt;

&lt;p&gt;Actually, this &lt;code&gt;docker&lt;/code&gt; keyword means your CircleCI build will be launched in a docker container instead of a Linux VM. After reading the whole documentation, you realize that you have to use a Linux VM to be able to use docker-compose with volumes (link: &lt;a href="https://circleci.com/docs/2.0/executor-types/" rel="noopener noreferrer"&gt;https://circleci.com/docs/2.0/executor-types/&lt;/a&gt; ).&lt;/p&gt;

&lt;p&gt;So let's create a new config file, step by step.&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# CircleCI version&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;machine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# Use a Linux VM instead of docker environment&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt; &lt;span class="c1"&gt;# Default working directory, where your project will be cloned&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we have a very basic install. Nice. Let's add a checkout of the repository.&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;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ..&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
        &lt;span class="c1"&gt;# Maybe you need to add some config file specific to circle…&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cp .circleci/.some-parameter-file .some-parameter-file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker-compose is by default installed on the Linux VM provided by CircleCI. We can directly build and up our 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;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ..&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# - …&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose up -d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can install the dependencies of your project. Here we have node (yarn) and PHP (composer) dependencies.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# - …&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php composer install -n --prefer-dist&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose run --rm front yarn install&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose run --rm front yarn build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run our tests!&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="c1"&gt;# run tests!&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# - …&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php vendor/bin/phpspec run -vvv&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec php ./vendor/bin/behat -v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tada! An extra bonus? Let's say you do some End2End testing and you take some screenshots when a test failed… Maybe you want to be able to access the screenshot (or log file) from the CircleCI interface? You can add a directory as an &lt;code&gt;artifact&lt;/code&gt;. This will be then available in the &lt;code&gt;artifacts&lt;/code&gt; link above your tests.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# …&lt;/span&gt;

        &lt;span class="c1"&gt;# This line is to be able to access failing screenshots in the&lt;/span&gt;
        &lt;span class="c1"&gt;# artifacts section in CircleCI&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo/features/fail-screenshots&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So cool! Now you have a CI running with docker-compose, using your dev environment. Pretty swag.&lt;br&gt;
Now, some of you may encounter permissions problems because of the users. This can be because CircleCI uses a user with id &lt;code&gt;1001&lt;/code&gt; and a group with id &lt;code&gt;1002&lt;/code&gt;. Sometimes in can conflict with your local permissions (your local user being &lt;code&gt;1000&lt;/code&gt; in general). If so, you can specify the user that will launch the docker command.&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# run tests!&lt;/span&gt;

        &lt;span class="c1"&gt;# Circleci uses a user with id 1001 and a group with id 1002&lt;/span&gt;
        &lt;span class="c1"&gt;# We use this user instead of the default one in our dockerfile (1000)&lt;/span&gt;
        &lt;span class="c1"&gt;# to avoid permissions issues&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec --user=1001:1002 php vendor/bin/phpspec run -vvv&lt;/span&gt;

        &lt;span class="c1"&gt;# We use the root user here to change logs and cache permissions&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec --user=root php chmod -R 777 var/logs&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker-compose exec --user=root php chmod -R 777 var/cache&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this article helped you to make this small green dot appear on your PRs :).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Using Gitlab? See &lt;a href="https://dev.to/einenlum/a-free-ci-using-docker-compose-for-your-gitlab-repositories-6po"&gt;here&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image credits: &lt;a href="https://www.flickr.com/photos/ingens/8882619935/" rel="noopener noreferrer"&gt;"Bricks in circle" by Alessandro Mancini&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>circleci</category>
      <category>testing</category>
      <category>docker</category>
      <category>dockercompose</category>
    </item>
    <item>
      <title>Job offers: Don't get lost along the way</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Tue, 09 Jan 2018 06:47:54 +0000</pubDate>
      <link>https://forem.com/einenlum/job-offers-dont-get-lost-along-the-way-ab6</link>
      <guid>https://forem.com/einenlum/job-offers-dont-get-lost-along-the-way-ab6</guid>
      <description>&lt;p&gt;Dear potential employers,&lt;/p&gt;

&lt;p&gt;I know your company is dealing with urgent issues. I know the market is quite rough at the moment. I know good developers have now high and diverse expectations: keeping track of these must not be easy.&lt;/p&gt;

&lt;p&gt;It seems like for some of you, free coffee or free candies are a must have. Available Nerf guns in the office are maybe the line in your job offer that will make your company stand out from the others.&lt;/p&gt;

&lt;p&gt;Maybe you're right. Maybe I totally underestimate this kind of features. But one thing that matters to me and that you &lt;strong&gt;often forget, is the technical stack&lt;/strong&gt; you want me to deal with.&lt;/p&gt;

&lt;p&gt;I'm not kidding. &lt;strong&gt;Some offers don't even mention one programming language&lt;/strong&gt;. You could think it's an exception and that I chose only small and dubious companies. You would be wrong.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://boards.greenhouse.io/reddit/jobs/655395?t=onmjps1#.WlRYj_ZG2Hs" rel="noopener noreferrer"&gt;job offer&lt;/a&gt; to work at Reddit.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmn8xry1frrh78ve8fw9.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmn8xry1frrh78ve8fw9.png" alt="A job offer to work for Reddit" width="800" height="1025"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seems all they want is &lt;em&gt;clean, maintainable, and well-tested code&lt;/em&gt;. You should know what it means, you, little &lt;em&gt;Backend&lt;/em&gt; developer. Does it include Node? Python? Ruby? Rust? PHP? Go? No one will know. I hope you are working to be familiar &lt;em&gt;with the whole web stack&lt;/em&gt;.&lt;br&gt;
Consider the list of all the things we know about this offer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pet Care Stipend&lt;/li&gt;
&lt;li&gt;Monthly Cell Phone Allowance&lt;/li&gt;
&lt;li&gt;Catered Meals &amp;amp; Snacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's great to know this. But I have the feeling that the authors got lost along the way. Please, next time, try not to forget to mention a few more details about the work I will be doing for you.  Write it down even at the very top of your job offer. It will save time to anyone.&lt;/p&gt;

</description>
      <category>career</category>
      <category>advice</category>
      <category>tips</category>
    </item>
    <item>
      <title>Lessons learned about Bus Factor (5/5): Detect it before it is too late</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 27 Sep 2017 15:08:59 +0000</pubDate>
      <link>https://forem.com/einenlum/lessons-learned-about-bus-factor-55-detect-it-before-it-is-too-late-dmi</link>
      <guid>https://forem.com/einenlum/lessons-learned-about-bus-factor-55-detect-it-before-it-is-too-late-dmi</guid>
      <description>&lt;p&gt;&lt;em&gt;This series of articles is taken from a talk I gave at the &lt;a href="https://twitter.com/bephpug" rel="noopener noreferrer"&gt;Berlin PHP Meetup&lt;/a&gt; and was originally posted on my &lt;a href="https://www.einenlum.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt;. If you didn’t read the first one, &lt;a href="https://www.einenlum.com/articles/bus-factor-1" rel="noopener noreferrer"&gt;here you go&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the past articles we wrote about the daily strategies you can set up to share knowledge, balance the level of your team and help anyone dive into your own code. It’s obviously essential to keep this issue in your mind on a daily basis. &lt;strong&gt;But now, is there a way to detect the Bus Factor of your project? How do you know another member of your team or a new developer could easily take up the reins of your project?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This question is crucial, since &lt;strong&gt;it is the kind of issue you generally detect when it is already too late&lt;/strong&gt; (remember my little story in the first article?). After a few fails, my colleagues and I didn’t want only to prevent these bad experiences in the future, but also to detect the projects where this could happen again.&lt;/p&gt;

&lt;p&gt;A year ago, during a hackathon, it led to a productive discussion between all the devs of my company. We ended up with a funny idea. &lt;strong&gt;Here is what we do, about every two weeks or every month.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bus Factor Review
&lt;/h2&gt;

&lt;p&gt;Take a project. Then &lt;strong&gt;take all the developers of your company who never worked on this project&lt;/strong&gt;. Only them. And you choose one of them, randomly.&lt;br&gt; &lt;strong&gt;Their goal is to&lt;/strong&gt; take about an hour or two, to clone your git repository, to install the project on their machine, and to &lt;strong&gt;understand the domain, and some implementation.&lt;/strong&gt; They can’t have any help from another developer. &lt;strong&gt;They can only rely on what is written in the repository&lt;/strong&gt;. If they find something to say (installation problems, obscure domain, strange and not documented architecture…), they open a Github issue and list the problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trust me, at first, some developers cannot even install the project&lt;/strong&gt;, because there is for example a mandatory parameter that was forgotten in the Readme. In this case, they just stop right there and write an issue. Then, two weeks later, you take another developer and he or she does the exact same thing. &lt;strong&gt;The idea is to detect things that are only said orally&lt;/strong&gt; and not documented in the repository. By doing it regularly in an iterative way, it does not take a lot of time, and it can help you detect a lot of implicit things.&lt;/p&gt;

&lt;p&gt;When you do this review, the idea is to imagine if someone wants you to add a new feature or to debug something in this project you don’t know. &lt;strong&gt;Would you be at ease to fix a bug or add a new feature in this project? If not, why?&lt;/strong&gt; What is this unusual pattern you don’t understand? What are these classes that are very badly named? Are the tests explicit enough?&lt;/p&gt;

&lt;p&gt;We all know that we tend to delay refactoring or writing documentation. “&lt;em&gt;Yeah, later&lt;/em&gt;”. &lt;strong&gt;We like to imagine ourselves in the last days of the project, cleaning everything that is dirty, writing a wonderful and explicit documentation, before we leave it to the client.&lt;/strong&gt; Oh, come on. Be honest. &lt;strong&gt;It never happens this way&lt;/strong&gt;, because &lt;em&gt;1/&lt;/em&gt; the last days of a project are in general stressful (because you’re close to a deadline or to the end of a budget) and &lt;em&gt;2/&lt;/em&gt; because you don’t remember all the “&lt;em&gt;wtf&lt;/em&gt;” implementations that would be obscure to a new comer. You got used to it. Testing regularly your project with a new look will force you to improve the quality of your code and documentation during the coding process. Moreover, the fact that different new people look at it will obviously help detecting various problems (every developer is not disconcerted by the exact same things).&lt;/p&gt;




&lt;h2&gt;
  
  
  To summarize
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Do systematic code reviews&lt;/li&gt;
&lt;li&gt;Give complex tasks also to the juniors but help them&lt;/li&gt;
&lt;li&gt;Stay close to the domain of your client&lt;/li&gt;
&lt;li&gt;Use high level tests reflecting your domain&lt;/li&gt;
&lt;li&gt;Write explicit code&lt;/li&gt;
&lt;li&gt;Detect a lack of shared knowledge as soon as possible, and write down everything in your repository/code. Stop this oral culture: act as if your private project was an open source project on which every unknown developer should be able to collaborate&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That’s it! I hope this series will help you in some ways. If you agree or disagree with a statement or use other techniques to increase the Bus Factor, please let me know! All comments are highly appreciated :).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Special thanks to Shivoham, Amandine and CÃ©cile for their ideas and proofreading)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture credits: "&lt;a href="https://www.flickr.com/photos/berlinbeyond2011/6193336443/in/photolist-arht9P-6bccio-deyFCp-goYfGz-a3vxHU-9PMyNq-9jvL7v-bqSFuF-cWe4RS-4zorW-jZfnqA-6b7gHM-9PMUqy-97EFj2-8QqYWP-85MRJV-8Zucvt-asv2K9-6eEXa5-85HZC7-7vUZKA-9gthGv-pKSGNX-2L49ss-a7hPTR-pnkMNn-a71YyV-mVS2hg-4LAmEu-jH3fq3-5ZZGTg-9PMyeQ-b9vkRP-qc1mPd-8CPEYK-C969c-8eKo2C-9PMPCw-4RBbZz-8tEGSS-aEfkPp-9Xm5NB-nCzkRf-7w8fih-9Gdu5A-9GajMX-nmitMv-9Gawov-nmivWv-9G9YdP" rel="noopener noreferrer"&gt;ThePollDiaries_003_BavariaFilmInternational&lt;/a&gt;" by Berlin Beyond.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>busfactor</category>
      <category>projectmanagement</category>
      <category>team</category>
      <category>development</category>
    </item>
    <item>
      <title>Lessons learned about Bus Factor (4/5): Stay close to the domain</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 27 Sep 2017 15:07:04 +0000</pubDate>
      <link>https://forem.com/einenlum/lessons-learned-about-bus-factor-45-stay-close-to-the-domain-b6h</link>
      <guid>https://forem.com/einenlum/lessons-learned-about-bus-factor-45-stay-close-to-the-domain-b6h</guid>
      <description>&lt;p&gt;&lt;em&gt;This series of articles is taken from a talk I gave at the &lt;a href="https://twitter.com/bephpug" rel="noopener noreferrer"&gt;Berlin PHP Meetup&lt;/a&gt; and was originally posted on my &lt;a href="https://www.einenlum.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt;. If you didn’t read the first one, &lt;a href="https://www.einenlum.com/articles/bus-factor-1" rel="noopener noreferrer"&gt;here you go&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(If the gist snippets don't show up, try to refresh the page. Seems dev.to is having some issues with it)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last time we saw how we could refactor code in a simple way to make it more obvious. We did not talk yet about your client’s domain. Maybe we should have done that in the first place.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stay close to the domain
&lt;/h2&gt;

&lt;p&gt;When you create a website for a client, you initially don’t know their job. It can be about printing, banking, shipping stuff… whatever. You’re not an expert of these fields. Even if you have knowledge in those, every company has their own vocabulary, processes and issues. &lt;strong&gt;Your first concern, when building a great application that is maintainable, should always be to understand the domain of your client.&lt;/strong&gt; Not only do you have to understand it, but it’s even better if you use the exact same words they use. This is called &lt;strong&gt;ubiquitous language&lt;/strong&gt;, and it’s a common concept in &lt;em&gt;Behavior Driven Development&lt;/em&gt; and in &lt;em&gt;Domain Driven Design&lt;/em&gt;. Using the same vocabulary as your client will avoid you wasting a lot of time translating what they are talking about. If you don’t know &lt;em&gt;Ubiquitous language&lt;/em&gt;, you can check &lt;a href="http://www.jamesshore.com/Agile-Book/ubiquitous_language.html" rel="noopener noreferrer"&gt;this nice article&lt;/a&gt; presenting this concept. Here are a few quotes from it, that summarize the key points, in my opinion.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can name your classes, methods, and variables anything. Why not use the terms that your domain experts use?&lt;br&gt; […]&lt;br&gt; &lt;em&gt;[Ubiquitous language]&lt;/em&gt; is reflecting in code how the users of the software think and speak about their work.&lt;br&gt; […]&lt;br&gt; Programmers should speak the language of their domain experts, not the other way around.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Sometimes you will even realize that your client has not a clear vocab for a few things.&lt;/strong&gt; Help them then, to find the best term to describe something and to keep always this same word as THE word. When you made all this work of understanding and translating your client language, please, &lt;strong&gt;write it down in a glossary&lt;/strong&gt;. It can be in a &lt;em&gt;Github&lt;/em&gt; wiki, or maybe better, directly in markdown pages put in the &lt;em&gt;doc&lt;/em&gt; section of your repository. &lt;strong&gt;Write there, all the important concepts of your client.&lt;/strong&gt; What is a &lt;em&gt;retailer&lt;/em&gt;? What is a &lt;em&gt;customer&lt;/em&gt;? How is defined an &lt;em&gt;invoice&lt;/em&gt;? What defines a &lt;em&gt;license&lt;/em&gt; and what is it used for? If your client does not speak english, write the matching between their terms and the terms used in the app (because yes, you will write your code in english. That should be obvious).&lt;/p&gt;

&lt;p&gt;This is a really important tool to help a new developer to understand the domain and its implementation in the code. Actually, &lt;strong&gt;if you write explicit code and stay as close as possible to the domain, a salesperson with no coding knowledge should be able to read your code and tell you if you’re implementing the logic in a good way&lt;/strong&gt;. It’s not always possible I got it. But &lt;strong&gt;that should be your ultimate goal.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Writing tests is also writing documentation
&lt;/h2&gt;

&lt;p&gt;It’s quite obvious that tests will help you improve the quality of your code and avoid bugs. Great. But &lt;strong&gt;tests can also be a great way to help a developer dive into your project&lt;/strong&gt;. &lt;strong&gt;The first thing I check when I dive into a new project, is the presence of functional tests.&lt;/strong&gt; That can make you understand very quickly what this application is about and what it does. And then, if I want to understand more in detail what different classes do, I can check unit tests. As a PHP developer I like to use &lt;a href="http://behat.org/en/latest/" rel="noopener noreferrer"&gt;Behat&lt;/a&gt; (a kind of Cucumber-like for those who are familiar with it), a simple test runner allowing you to describe &lt;em&gt;scenarios&lt;/em&gt; in a human readable language called &lt;em&gt;Gherkin&lt;/em&gt;. Here is how it looks like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Every &lt;em&gt;feature&lt;/em&gt; is a list of &lt;em&gt;scenarios&lt;/em&gt;, describing a specific user journey. &lt;em&gt;Given&lt;/em&gt; and &lt;em&gt;When&lt;/em&gt; statements describe an action. &lt;em&gt;Then&lt;/em&gt; statements decribe an expected result (what we also call an &lt;em&gt;assertion&lt;/em&gt;). Behat (or any Cucumber-like tool) will parse these *&lt;em&gt;.feature&lt;/em&gt; files and launch your scenarios one after another, by translating all these Given, When, Then, into concrete code you implemented. Behat will do that thanks to PHP annotations, but the other tools and language implementations are very similar.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;These tools are just test runners that let you free to write very explicit and simple tests scenarios, that every human understands. &lt;strong&gt;This allows you to write these scenarios with your non-dev client when they ask you to do a new feature, and to help any new comer in the project to understand what the application is about.&lt;/strong&gt; Cucumber-like tools and Gherkin are amazing to clarify your project.&lt;br&gt;
The problem is that these tools allow you to do many &lt;strong&gt;many&lt;/strong&gt; things, from scratch. Like manipulating a browser with already written Gherkin definitions. So usually, when looking at Behat tests, here is the kind of scenarios you could find in many projects.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Sure, it describes something. But it does not describe your domain. It describes a user journey thanks to a user interface, without really explaining the business rules.&lt;/p&gt;

&lt;p&gt;First, since it is totally coupled to the user interface, what happens if you’re working on a foreign project? Maybe you will start to see these kinds of things:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Wuuuh. Ugly. As a french developer I can assure you it’s a quite common thing to see. But the most serious problem here, is that &lt;strong&gt;you lose the main topic of documentation you should care about: the domain of your client.&lt;/strong&gt; Gherkin is a great tool, if you only describe the goal of the application in domain terms, without worrying at all about the concrete technical implementation. This scenario could be implemented with a classical website, a JSON Rest API, or a simple CLI. That is not our problem here. &lt;strong&gt;We want to describe where and why your mean of transportation is driving you. Not the colour of your car.&lt;/strong&gt; Here is how we could describe our feature instead:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;How is it implemented? HTTP? Shell? Whatever. We don’t care on this level. Here you can really describe the business logic of your app, and check with your client if you really understood the additional value of their project. What’s even greater, is that &lt;strong&gt;it allows you to test the same scenario in different ways&lt;/strong&gt; (end-to-end test with Selenium, infrastructure tests on the application layer…): these tools allow you to &lt;em&gt;tag&lt;/em&gt; (&lt;em&gt;@ui&lt;/em&gt; or &lt;em&gt;@integration&lt;/em&gt;, for example) your features and scenarios and send these features to different layers of testing.&lt;/p&gt;

&lt;p&gt;For those who want to go further, &lt;strong&gt;I really advise you the article “&lt;/strong&gt;&lt;a href="http://stakeholderwhisperer.com/posts/2014/10/introducing-modelling-by-example" rel="noopener noreferrer"&gt;Introducing Modelling by Example&lt;/a&gt;&lt;strong&gt;”&lt;/strong&gt; by &lt;a href="https://medium.com/@everzet" rel="noopener noreferrer"&gt;everzet&lt;/a&gt; (the creator of Behat) which explains much better and deeper what I just said (among other things). Also, if you want to know how it looks like to use Behat (or any Cucumber-like tool) the wrong way, I encourage you to read “&lt;a href="http://codeception.com/12-20-2012/not-bdd.html" rel="noopener noreferrer"&gt;Stop Simulating BDD, Write Tests&lt;/a&gt; from &lt;em&gt;Codeception’s&lt;/em&gt; blog (Codeception is another PHP test framework). Don’t get me wrong: I’m not saying Codeception is a bad tool or that Behat is necessarily better (I never worked with Codeception). I’m just saying the given arguments show a total misconception of the tool. This article shows the worst way to use Behat, so in the end we could say it’s a great article because it’s very instructive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Staying as close to the domain as possible, and documenting the main goals of your app in a business language will help anyone to dive into your project and understand right away why all this has been built.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/einenlum/lessons-learned-about-bus-factor-55-detect-it-before-it-is-too-late-dmi"&gt;In the next (and final) article&lt;/a&gt;, we will think about how we can detect a Bus Factor issue as quick as possible.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image credits: "The Entire City" by Max Ernst.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>busfactor</category>
      <category>code</category>
      <category>domain</category>
      <category>development</category>
    </item>
    <item>
      <title>Lessons learned about Bus Factor (3/5): Write explicit code</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 27 Sep 2017 15:06:04 +0000</pubDate>
      <link>https://forem.com/einenlum/lessons-learned-about-bus-factor-35-write-explicit-code-38l</link>
      <guid>https://forem.com/einenlum/lessons-learned-about-bus-factor-35-write-explicit-code-38l</guid>
      <description>&lt;p&gt;&lt;em&gt;This series of articles is taken from a talk I gave at the &lt;a href="https://twitter.com/bephpug" rel="noopener noreferrer"&gt;Berlin PHP Meetup&lt;/a&gt; and was originally posted on my &lt;a href="https://www.einenlum.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt;. If you didn't read the first one, &lt;a href="https://www.einenlum.com/articles/bus-factor-1" rel="noopener noreferrer"&gt;here you go&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Dev.to has some issues with my Gists. It scrambles them! You should definitely read this article &lt;a href="https://www.einenlum.com/articles/bus-factor-3" rel="noopener noreferrer"&gt;here&lt;/a&gt; instead.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Write explicit code
&lt;/h2&gt;

&lt;p&gt;Last time we talked about the strategies you could set up to share knowledge within your current coding team. It's great, but it would be even better to help &lt;em&gt;anyone&lt;/em&gt; to read your code and understand your implementation right away. &lt;strong&gt;Let's dive into some concrete code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say you are new on a project and you have to add a new feature in this part of PHP code below. &lt;strong&gt;I know, it's PHP. But don't leave. It's a basic one, and even if you hate that language, it should not be a problem to understand what is going on. These considerations should apply to almost any language and code.&lt;/strong&gt; This is a dummy example I wrote, to reflect the kind of usual bad code you can find when you join a random project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try to understand what this code is about, in a few seconds.&lt;/strong&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Ok, I think you got it: the previous code is about calculating shipping fees. But that was not so obvious to get, and still, it is a very simple and short class. Imagine how it can feel for a newcomer in your project if there are hundreds of classes like this, and five times as long as this one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's try to clarify that.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, &lt;strong&gt;the naming is very bad.&lt;/strong&gt; &lt;em&gt;Service&lt;/em&gt; does not mean anything and the method name is not explicit enough. We rename the namespace, the class and the method &lt;em&gt;(l. 3, 5, 14)&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Better. Now the next problem is that &lt;strong&gt;a Calculator should calculate and return a value&lt;/strong&gt;. Here, it calculates and sets the value to an object. This is misleading, and multiplies the responsibilities of the class. It also finds the &lt;em&gt;Cart&lt;/em&gt; object from a repository: it is quite hard to defend the injection of a repository in this simple &lt;em&gt;Calculator&lt;/em&gt; class. &lt;strong&gt;Let's directly pass a Cart object as parameter (allowing an explicit typehint) and just return the calculated value&lt;/strong&gt; &lt;em&gt;(l. 9, 29)&lt;/em&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;This if/elseif is confusing&lt;/strong&gt; and takes too much of my energy to follow. Let's get rid of that &lt;em&gt;(l. 21 and 29)&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I feel better already. &lt;strong&gt;This calculation of the total of the cart could be the responsibility of the model.&lt;/strong&gt; Then let's get rid of it too, and add an explicit method name so that we know what total we are talking about (because yes, &lt;strong&gt;when calculating prices, knowing if we include VAT or not can be interesting&lt;/strong&gt;) &lt;em&gt;(l.13)&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I still have an issue here. &lt;strong&gt;What are all these magical numbers? 20? 40? 100?&lt;/strong&gt; If you are new to the project, chances are that you will be a bit afraid to change one of them and will ask to your client or your colleagues what they actually mean. If they are supposed to change, we inject them as parameters with clear variable names. If they are not, then &lt;strong&gt;we can use constants&lt;/strong&gt; &lt;em&gt;(l. 11, 17, 22, 25)&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This could look a bit overkill to use constants here, but it will help for sure any new comer to the project to understand right away what is going on. Even better: &lt;strong&gt;if you have a question about these numbers, you can directly ask your client about the &lt;em&gt;threshold for free shipping fees&lt;/em&gt; instead of making them guess about this &lt;em&gt;100 number&lt;/em&gt; that could be anything in the app. Finally **it allows you to centralize these informations somewhere and reuse them in the app&lt;/strong&gt;, avoiding you some headaches while refactoring.&lt;/p&gt;

&lt;p&gt;This is way better. But I still have a last issue here. I guess these numbers are some money. &lt;strong&gt;But with what currency are we working here?&lt;/strong&gt; Euros? Dollars? Yen? If you clarify this right away, that will prevent every developer from being lost when the app is growing. For this, we can use the &lt;a href="https://github.com/moneyphp/money" rel="noopener noreferrer"&gt;Money library&lt;/a&gt; which implements &lt;a href="https://martinfowler.com/eaaCatalog/money.html" rel="noopener noreferrer"&gt;Martin's Fowler Money pattern&lt;/a&gt;. We also add a &lt;em&gt;return typehint&lt;/em&gt;, since we can do it since PHP 7.1 &lt;em&gt;(l.5, 14, 18 and 26)&lt;/em&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If it is maybe as verbose as the initial code, I think this code is much easier to read, to understand and to maintain. &lt;strong&gt;You understand right away what we are talking about and what it does, without the need of any comment.&lt;/strong&gt; This will also (in my opinion) &lt;strong&gt;help a lot of new comers in your project to dive into your code and be able to refactor or maintain any class.&lt;/strong&gt; It will &lt;strong&gt;avoid&lt;/strong&gt; the team to waste time with &lt;strong&gt;infinite questions, since the code is self-documented.&lt;/strong&gt; This is obviously a very simple example I took for the purpose of this article, but I think this way of refactoring and writing explicit code can apply to much fatter classes. Also this &lt;em&gt;Calculator&lt;/em&gt; is a dummy example: we could (should?) do that directly in the model instead of instantiating a service for this simple task. Once again, it was just a straightforward example to show a few common problems we can find on a daily basis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/einenlum/lessons-learned-about-bus-factor-45-stay-close-to-the-domain-b6h"&gt;Next time&lt;/a&gt;, we will talk about one of the most important issues when lacking of knowledge sharing: &lt;strong&gt;the domain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture credits: "&lt;a href="https://www.flickr.com/photos/europeanspaceagency/11337951926/in/album-72157623547766194/" rel="noopener noreferrer"&gt;Juventae Chasma&lt;/a&gt;" by European Space Agency.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>busfactor</category>
      <category>code</category>
      <category>php</category>
      <category>development</category>
    </item>
    <item>
      <title>Lessons learned about Bus Factor (2/5): Balancing the level of your team</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 27 Sep 2017 15:04:41 +0000</pubDate>
      <link>https://forem.com/einenlum/lessons-learned-about-bus-factor-25-balancing-the-level-of-your-team-634</link>
      <guid>https://forem.com/einenlum/lessons-learned-about-bus-factor-25-balancing-the-level-of-your-team-634</guid>
      <description>&lt;p&gt;&lt;em&gt;This series of articles is taken from a talk I gave at the &lt;a href="https://twitter.com/bephpug" rel="noopener noreferrer"&gt;Berlin PHP Meetup&lt;/a&gt; and was originally posted on my &lt;a href="https://www.einenlum.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This cute kitten has absolutely nothing to do with&lt;/em&gt; Bus Factor, &lt;strong&gt;&lt;em&gt;unlike&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://dev.to/einenlum/lessons-learned-about-bus-factor-15-introduction-dl0"&gt;the first post of this series&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now we’re here, let’s dive into the lessons I learned about how to share knowledge &lt;em&gt;inside your current coding team&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Code Reviews
&lt;/h2&gt;

&lt;p&gt;I know this one is a big classic in the industry, but I think it is always good to emphasize it as a general advice. &lt;strong&gt;At &lt;a href="http://knplabs.com/" rel="noopener noreferrer"&gt;KNPLabs&lt;/a&gt; (the company I work in), we automatically do a code review for every feature or every fix. You can’t merge your own pull requests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why that?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, it’s obviously a question of &lt;strong&gt;quality of code&lt;/strong&gt;. Code reviews help detecting bugs and prevent bad implementations.&lt;/li&gt;
&lt;li&gt;Second, it will teach you new ways to code, or to solve a problem and it will &lt;strong&gt;ensure that at least another developer has seen what is going on in this part of the application&lt;/strong&gt; (if your application is growing fast, there is a chance you don’t keep track of important changes or implementations).&lt;/li&gt;
&lt;li&gt;And finally, a part that seems really important to me: it helps &lt;strong&gt;reducing tensions within the team&lt;/strong&gt;. If you introduced a bug in the app, you’re not the only one responsible for it. &lt;em&gt;The whole team&lt;/em&gt; is responsible. This way you can’t tell “&lt;em&gt;This guy or this girl did that&lt;/em&gt;”. The one who merges it is equally responsible. You will then &lt;strong&gt;share fails and victories together&lt;/strong&gt;. I do trainings sometimes and I am always shocked by how the coding and merging process can influence on the global ambiance. &lt;strong&gt;A mandatory code review process does not ensure by itself a friendly and united team. But no process at all with no shared responsibility between developers guarantees tensions, for sure.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code reviews are definitely a great tool. But it is not enough. Because we all know this moment when you’re tired and stressed and you have to review 2000 lines of code at 6pm. In this case you sometimes close your eyes on something you don’t understand cause you know… “&lt;em&gt;f*** it, let’s merge it&lt;/em&gt;”. &lt;strong&gt;If you have fat pull requests to review, it is a good idea to ask your colleague to present you their work and to review it in pair&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Improve the level of your juniors&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s say you have two seniors in your team and one junior. Here is what usually happens.&lt;/p&gt;

&lt;p&gt;You are doing your sprint planning and you have 3 features/fix requests.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implementing a catalog import with &lt;em&gt;RabbitMQ&lt;/em&gt; and &lt;em&gt;Elasticsearch&lt;/em&gt; (I took that example randomly, for sure)&lt;/li&gt;
&lt;li&gt;Synchronizing two databases&lt;/li&gt;
&lt;li&gt;Fixing a lot of broken translations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two first are complex ones. The final one is a simple (but quite boring) task. &lt;strong&gt;Right now, the junior developer is panicking cause they don’t have any clue how to handle the two complex tasks and they hope they are not asked to do these tasks&lt;/strong&gt;. Well, actually it’s not a problem, because the two senior developers are already discussing how fun it will be to deal with these complex issues, and start talking about a new esoteric and exciting paradigm they want to try. The junior is relieved and every one is happy…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For now&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Because &lt;strong&gt;sooner or later, this junior developer will probably have to dive alone into this code&lt;/strong&gt;, and spend a stressful day first trying to understand the implementation and then trying to fix it. And we’re back to my little story from the beginning. Also, &lt;strong&gt;if we always give the most simple tasks to our junior developers, how can we expect them to level up?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is a simple but smart solution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do not always give the most complex thing to do, to the best developer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Regularly (not always), ask your junior developer, if they agree, to take one of the most complex tasks.&lt;/strong&gt; The fact that they take it does not mean at all that they must be alone on this. &lt;strong&gt;Tell them that they can ask you any questions they want at any point, and that you can do pair programming with them to solve this problem.&lt;/strong&gt; Make everyone comfortable, and explain to the junior that it’s obviously not a shame if they have no clue how to do this. We all start at one point, and there is no problem being lost with a new technology or paradigm.&lt;br&gt;
In general the junior developer will accept the offer, with a bit of fear. They will be very happy soon to have responsibilities in this team and to finally understand this new pattern or language.&lt;/p&gt;

&lt;p&gt;Pair programming is a great tool, because (unlike code reviews) it does not only give you the result, but also the process of thought of your colleagues. If I think about my own experience, &lt;strong&gt;pair programming or just discussing with a more experimented developer about a future feature were the most rewarding moments in my short career.&lt;/strong&gt; These moments are probably the ones when we learn the most how to think and code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/einenlum/lessons-learned-about-bus-factor-35-write-explicit-code-38l"&gt;Next time&lt;/a&gt;, we will see how to make our code more explicit to ensure that a new comer will find their way in it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture credits: "&lt;a href="https://www.flickr.com/photos/allenran917/16224088376/in/photolist-qHEGeE-VvqqLn-8wjaRr-XBfaFB-dvbKrw-reYMzZ-f8L8za-7T8hsP-oJ9ZmW-7fWQeE-6cBTLH-6n6PFy-4p76dD-h7n8mb-9z3L7m-9yZN48-8PSbV5-QJ4NT-qnB4i6-56MRLC-9z3ZZ3-Yre7ZC-6RuxBJ-96aT2f-DoQwgw-UcKdeK-D68hy-9yZWfx-hePhKB-q8FCQV-7RshHy-VePL8z-S4VZXy-Z3qFfn-5HJCVZ-4tHLYi-rnnX9-bnVk8W-8gSzjF-6oac8U-pr2qUB-b1CqCF-8PP7NT-9yZB92-TAK4RF-rgrduM-QQjxJY-g7g4bu-qkv56h-q6eoDQ" rel="noopener noreferrer"&gt;_DSC2079&lt;/a&gt;" by allenran 917.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>busfactor</category>
      <category>projectmanagement</category>
      <category>team</category>
      <category>development</category>
    </item>
    <item>
      <title>Lessons learned about Bus Factor (1/5): Introduction</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 27 Sep 2017 15:03:04 +0000</pubDate>
      <link>https://forem.com/einenlum/lessons-learned-about-bus-factor-15-introduction-dl0</link>
      <guid>https://forem.com/einenlum/lessons-learned-about-bus-factor-15-introduction-dl0</guid>
      <description>&lt;p&gt;&lt;em&gt;This series of articles is taken from a talk I gave at the &lt;a href="https://twitter.com/bephpug" rel="noopener noreferrer"&gt;Berlin PHP Meetup&lt;/a&gt; and was originally posted on my &lt;a href="https://www.einenlum.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let me share with you a little story of mine. About 2 years ago, I was working on a quite complex project to create a marketplace from scratch. We were two on the job, and my colleague was a much more experienced developer than I was. We finally made this app and released it. A few months after that, we had a bug in production concerning catalog importation, involving a complex system working with &lt;em&gt;RabbitMQ&lt;/em&gt; and &lt;em&gt;Elasticsearch&lt;/em&gt;. I had never touched that part of code. And my colleague was on holidays. I was designated to fix it. Cause you know… “&lt;strong&gt;you worked on this project, right?&lt;/strong&gt;”. Sure.&lt;/p&gt;

&lt;p&gt;The reality is that I didn’t know at the time how all this worked and I found myself completely lost and panicked to understand all this stack. In the end, I didn’t manage to fix that bug. It led to frustration, stress and loss of confidence from myself, my colleagues and my client. That was a &lt;strong&gt;horrible&lt;/strong&gt; experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sounds familiar to you? If so, this series of articles is for you.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Bus Factor?
&lt;/h2&gt;

&lt;p&gt;You can find several slightly different definitions of the &lt;em&gt;Bus Factor&lt;/em&gt; on the web. Let’s make a patchwork.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The bus factor is the total number of developers who would need to be incapacitated, as by getting hit by a bus, so that the project would be left for dead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words, &lt;strong&gt;the bus factor estimates the number of developers that are vital to a project&lt;/strong&gt;, for any reason (lack of understanding of their implementation or information withholding). If those developers are gone (on holidays, fired, or just away), no one is able to maintain the project or to add new features anymore. In technical terms, that could be considered as &lt;strong&gt;detecting the single point of failure within the team.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This little thought experiment can help you to detect this kind of situation before it happens. If you have a bus factor of 1 (which means that with just one developer away, your team does not feel like it can maintain the project), then you have a serious problem. &lt;strong&gt;The goal is to increase this bus factor to the maximum and to share knowledge so that you can prevent your project from falling apart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this series of articles, I will try to give you a few lessons I learned about knowledge sharing within your coding team, and also outside your coding team.&lt;/strong&gt; Because you would like all your colleagues (even the ones working on different projects) to be able to help you at one point. Or just because it also applies for when your client decides to put their own developers on the project. You don’t want them to be stuck and to contact you every two weeks. Even if they don’t contact you, you don’t want other developers to feel the same way as I did (because you’re a good person. I know it). In the very next article I will present the essential ways of sharing knowledge &lt;em&gt;inside&lt;/em&gt; your team. This will be followed by two other articles about strategies that apply for every developer outside your team, and finally by a bonus article about detecting as soon as possible a &lt;em&gt;Bus Factor&lt;/em&gt; issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next is available &lt;a href="https://dev.to/einenlum/lessons-learned-about-bus-factor-25-balancing-the-level-of-your-team-634"&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Picture credits: "&lt;a href="https://www.flickr.com/photos/seattlemunicipalarchives/3797940793/in/photolist-6MBrtP-jCkPQA-Pg1wM-6w5ojz-4S3mXh-Pfumb-Pfumh-8Tk1KJ-g4Wxfq-o9rTmn-4CgbzH-4Cgbt6-7nc8tZ-4RYcEg-npSWRM-viWdm9-Pg1x4-TK3nj7-7NSPXP-9qUgQS-5ZTghs-4RYufn-8Qcfhi-ADuSK-9t9gFc-Pg1x8-9t9ifz-Pg144-cTEXp9-7yKiEj-gGzaeE-aEBvcp-4XJsbd-7NWMFN-Pfsgo-Pg142-4Rpopg-6YZVae-6Z4C5J-WHFT-WHFR-4ncFVs-4t3rAA-5icH3G-UCLwzN-8QfVf7-4S3kw7-7BB4Fs-UC1hvP-fTchtM" rel="noopener noreferrer"&gt;Bus accident on Empire Way, 1933&lt;/a&gt;" by Seattle Municipal Archives.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>busfactor</category>
      <category>projectmanagement</category>
      <category>team</category>
      <category>development</category>
    </item>
    <item>
      <title>Nice to meet you, buddy.</title>
      <dc:creator>Yann Rabiller</dc:creator>
      <pubDate>Wed, 15 Feb 2017 12:39:21 +0000</pubDate>
      <link>https://forem.com/einenlum/nice-to-meet-you-buddy</link>
      <guid>https://forem.com/einenlum/nice-to-meet-you-buddy</guid>
      <description>&lt;p&gt;PHP/Symfony developer and trainer at KNPLabs. Living in Berlin right now.&lt;br&gt;
You can find me on Twitter as &lt;a href="https://twitter.com/Einenlum" rel="noopener noreferrer"&gt;@Einenlum&lt;/a&gt;&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
