Jekyll2021-04-25T11:07:09-05:00https://blog.francoisfaubert.com/feed.xmlA strange reluctance to be criticalThe blog of Francois Faubert a web developper from Montreal, Canada.
The Hanselman Effect2020-05-13T01:00:00-05:002020-05-13T01:00:00-05:00https://blog.francoisfaubert.com/2020/05/13/the-hanselman-effect<p>Today is the first day of <a href="https://mybuild.microsoft.com/">Microsoft Build 2020</a>, an event tailored for developers which features the most recent technologies and tools created, supported, or encouraged by Microsoft.</p>
<p>Because of the ongoing COVID-19 social distancing in place, this year’s edition of the conference is to be 100% streamed online.</p>
<p>I have recently received a gift box from Microsoft because I was an early registrant to the conference (by chance). Seeing how it is a free conference, I was very surprised by the care package and shared it on Twitter :</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Unexpected delivery of <a href="https://twitter.com/hashtag/MSBuild?src=hash&ref_src=twsrc%5Etfw">#MSBuild</a> swag package this morning. Thanks <a href="https://twitter.com/Microsoft?ref_src=twsrc%5Etfw">@Microsoft</a>! <a href="https://t.co/J0ejISqLg8">pic.twitter.com/J0ejISqLg8</a></p>— Francois Faubert (@francoisfaubert) <a href="https://twitter.com/francoisfaubert/status/1258795996454236162?ref_src=twsrc%5Etfw">May 8, 2020</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>I was lucky enough for my tweet to be noticed and retweeted by Microsoft’s <a href="https://www.hanselman.com/">Scott Hanselman</a>. As a core speaker at most Microsoft events for software developers, he is arguably one of their most famous public figures and certainly one their best technology advocate.</p>
<p>What I appreciate most in Scott is the apparent lack of employer bias that one may be forgiven to expect in a blogger in his position.</p>
<h1 id="the-the-hanselman-effect-experience">The <em>The Hanselman Effect</em> experience</h1>
<p>Here’s what happens when a guy like him retweets you and you get to experience what I am calling <em>The Hanselman Effect</em>:</p>
<table>
<thead>
<tr>
<th>What</th>
<th style="text-align: right">How many</th>
</tr>
</thead>
<tbody>
<tr>
<td>Times people saw my tweet</td>
<td style="text-align: right">49,963</td>
</tr>
<tr>
<td>Likes</td>
<td style="text-align: right">194</td>
</tr>
<tr>
<td>Replies</td>
<td style="text-align: right">19</td>
</tr>
<tr>
<td>Retweets</td>
<td style="text-align: right">10</td>
</tr>
<tr>
<td>Profile clicks</td>
<td style="text-align: right">462</td>
</tr>
</tbody>
</table>
<p>Through this, I gained <em>8 new followers</em> which will undoubtedly be disappointed to see <a href="https://twitter.com/TrapLarge/status/1251717720787181569">what I usually tweet about</a>.</p>
<p>While I am impressed by the amount of times my tweet has been read as a whole, I know very well that nothing will come out of that kind of exposure.</p>
<p>None of these people will remember me from this retweet by now. It’s really how it should be, honestly. It’s not like they were attracted by content I was pushing out, for exemple.</p>
<p>What I find even more interesting however is the number of times my profile was viewed during this period. In theory, was I doing something special, these would have been people I never could have reached otherwise.</p>
<h1 id="dealing-with-this-exposure-daily">Dealing with this exposure daily?</h1>
<p>But wow! Almost 50K+ views from an offhand retweet.</p>
<p>Imagine for a second what popular people like Scott have to deal with every day. Tons of people they don’t know connecting with him all the time, each sharing thoughts they figure is important.</p>
<p>…and we all know how weird people can get on the internet.</p>
<p>I’ve always expected the effects of being able to reach (and be reached) such a crowd to sum up being negative.</p>
<p>Imagine what happens when <a href="https://pagesix.com/2018/06/05/star-wars-actress-kelly-marie-tran-quits-social-media-after-harassment/">things turn sour</a> and you have hundreds of people actively attacking you. Sure, there has to be moment where being internet famous must be pretty cool, but, for some, <a href="https://pitchfork.com/news/36081-reznor-explains-why-he-quit-twitter/">it does not</a> <a href="https://www.livescience.com/51294-cyberbullying-social-media-teen-depression.html">balance out</a>.</p>Today is the first day of Microsoft Build 2020, an event tailored for developers which features the most recent technologies and tools created, supported, or encouraged by Microsoft.Creating Docker container images of Jekyll applications2020-03-10T01:00:00-05:002020-03-10T01:00:00-05:00https://blog.francoisfaubert.com/2020/03/10/docker-container-jekyll-applications<p><a href="https://jekyllrb.com/">Jekyll</a> is a simple static website generator made in Ruby, famous for being the preferred tool for publishing <a href="https://pages.github.com/">GitHub Pages</a>.</p>
<p>Though the Jekyll/GitHub relationship may feel like the natural setup, there are times when one might want to save a compiled Jekyll project into a container for it to be deployed on another platform.</p>
<p>One of the reasons you may want to do that is to circumvent the limitations of the allowed plugins on GitHub pages. Additionally, you may wish to fine-tune how your application is being served by customizing server headers and such.</p>
<p>In my case I am using the configuration described here to publish a container’d versions of my blog on a <a href="http://dokku.viewdocs.io/dokku/">Dokku</a> installation.</p>
<h1 id="dockerfile">Dockerfile</h1>
<p>Start by creating a <code class="highlighter-rouge">Dockerfile</code> at the root of your Jekyll application. The file will be very simple since it only has to define how to build the project files and define a way to serve them.</p>
<p>Here is the <code class="highlighter-rouge">Dockerfile</code> configuration used by this blog :</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FROM jekyll/builder AS build
WORKDIR /app
COPY . .
RUN mkdir .jekyll-cache _site \
&& jekyll build --trace
FROM nginx
COPY --from=build /app/_site /usr/share/nginx/html
EXPOSE 80
</code></pre></div></div>
<p>Notice that the container is exposing port <code class="highlighter-rouge">80</code> because serving <code class="highlighter-rouge">https</code> (<code class="highlighter-rouge">443</code>) and managing SSL certificates is being handled by the container orchestrator or a reverse proxy installed in it.</p>
<p>In my case, this is being handled by Dokku, but it could be the <a href="https://www.nginx.com/products/nginx/kubernetes-ingress-controller/">Kubernetes Ingress Controller</a>, <a href="https://docs.traefik.io/">Traefik</a> or another of these types of tools.</p>
<p>From there you may create the container with the <code class="highlighter-rouge">docker build</code> command:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker build <span class="nt">-t</span> my_jekyll_application:latest <span class="nb">.</span>
</code></pre></div></div>
<h1 id="maintenance--development">Maintenance & development</h1>
<p>While you are at it, you might as well do everything in a container and skip installing Ruby and Jekyll on your machine altogether.</p>
<p>The commands are well documented in the <a href="https://github.com/envygeeks/jekyll-docker#readme">builder image’s documentation</a>, but here are two useful invocations that I use repeatedly:</p>
<p>Update the application’s <code class="highlighter-rouge">Gemfile</code>:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--rm</span> <span class="nt">-v</span> <span class="k">${</span><span class="nv">pwd</span><span class="k">}</span>:/srv/jekyll <span class="nt">-v</span> <span class="k">${</span><span class="nv">pwd</span><span class="k">}</span>/vendor/bundle:/usr/local/bundle <span class="nt">-it</span> jekyll/builder:3.8 bundle update
</code></pre></div></div>
<p>Develop applications with live refresh:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>docker run <span class="nt">--rm</span> <span class="nt">-v</span> <span class="k">${</span><span class="nv">pwd</span><span class="k">}</span>:/srv/jekyll <span class="nt">-v</span> <span class="k">${</span><span class="nv">pwd</span><span class="k">}</span>/vendor/bundle:/usr/local/bundle <span class="nt">-p</span> 4000:4000 <span class="nt">-it</span> jekyll/builder:3.8 jekyll serve
</code></pre></div></div>Jekyll is a simple static website generator made in Ruby, famous for being the preferred tool for publishing GitHub Pages.Strata Reaches End of Life2019-12-06T00:00:00-06:002019-12-06T00:00:00-06:00https://blog.francoisfaubert.com/2019/12/06/strata-end-of-life<p>After years of having been largely ignored, I am archiving the <a href="https://github.com/strata-mvc">Strata project</a>.</p>
<p>Even though I know for a fact that nobody is using the library from looking at its <a href="https://packagist.org/packages/strata-mvc/strata">Packagist install statistics</a>, it is now official that you should not consider it to build your next project.</p>
<p>The reasons for the deprecation are twofold:</p>
<ul>
<li>I have not been in a position where I have to make Wordpress behave like a full-fledged CMS for a while now.</li>
<li>I have no interest in maintaining a project that found no traction in the community.</li>
</ul>
<p>Alternatives to parts of what Strata was trying to achieve can be found in <a href="https://roots.io/">Roots.io</a>, of whom <a href="https://roots.io/bedrock/">Bedrock</a> was an inspiration for Strata’s project structure.</p>
<p>In cases where your projects need a CMS running on PHP and MySQL that also has <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a> capabilities, then <a href="https://craftcms.com/">Craft CMS</a> is probably the best choice on the market for your needs depending on scope.</p>
<h1 id="things-are-still-pretty-bad-though">Things are still pretty bad though</h1>
<p>While <em>I</em> no longer wish to modernize PHP and Wordpress development, it doesn’t mean they have no room for improvement.</p>
<p>Nothing has changed regarding Wordpress’s technical implementation in these last years.</p>
<h2 id="lets-move-on">Let’s move on</h2>
<p>Nowadays I don’t recommend Wordpress for anything. I never really did, to be honest, but now I have the luxury of not having to use it… and I feel sorry for those who must.</p>
<p>I find the blogging tool to be a poorly implemented solution using legacy coding patterns written in a language that has trouble modernizing.</p>
<p>This description of Wordpress really shouldn’t be a surprise for any seasoned developer. Out of the box, the blog engine still won’t support Composer for versioning, it won’t ship with content translation management even though it features static translations, and it relies on events that can potentially be overridden in absolutely unmaintainable ways – whether or not that code is object-oriented.</p>
<h2 id="usage-is-not-a-sign-of-quality">Usage is not a sign of quality</h2>
<p>One ironic realization that came to me while building on Wordpress was that the vast quantity of available plugins is often used as a selling point, but they are often more a hindrance in practice.</p>
<p>To be clear some do work fine. The big ones like <a href="https://www.advancedcustomfields.com/">Advanced Custom Fields</a> are awesome but, like Strata, I feel they are trying to improve boat that does not quite float.</p>
<p>In truth, the plugins you install on a site quickly become a liability because they are often security disasters waiting to happen. That’s when they fully enable the feature your project needs to start with.</p>
<h1 id="for-the-brave-strata-is-easy-to-copy">For the brave, Strata is easy to copy</h1>
<p>What Strata enabled can easily be added to the Wordpress core if they cared. All in all, Strata was really just an event hook that registered early in the rendering pipeline that would route URLs to controller classes.</p>
<p>It is true that we did clever Custom Post Type autoloading and that our controllers could override the templating engine to allow custom response types (ex: JSON, file downloads, etc.) which Wordpress would have a hard time refactoring in.</p>
<p>They would still have a better platform with a fraction of the features granted by Strata though. I am surprised they are not trying harder by now.</p>
<h2 id="routing-worked-great">Routing worked great</h2>
<p>In hindsight, especially because of translations, I would probably route on the template key used by a custom post type rather than its slug. I would also rebuild the router using Symfony components instead of the pattern matcher we were using.</p>
<p>No matter the details, it is hard to argue against routing actions, filters, events and custom post types to dedicated controllers classes as an elegant way of keeping your code organized while leaving logic out of the templates.</p>
<h2 id="custom-post-type-as-models">Custom Post Type as Models</h2>
<p>This is where I think you got the most value out of Strata.</p>
<p>Considering each Custom Post Types as a model, we were able to create an abstraction to the database that hid Wordpress’ raw database queries.</p>
<p>You could query your posts with an almost ORM type API and invoke Active Record-like methods on the obtained result’s elements. Those clearly defined boundaries between your model queries and your model entity manipulations.</p>
<p>That was incredibly useful and I was able to deliver complex functionality easily with that and basic class inheritance.</p>
<h1 id="goodbye">Goodbye</h1>
<p>And so this is it, goodbye Strata. I have learned a lot from building you.</p>
<p>I am sad that Strata has not attracted more developers, but I would not want to maintain it at this point anyways. Not while Wordpress continues being… Wordpress.</p>After years of having been largely ignored, I am archiving the Strata project.I’m loving .NET Core2018-07-30T01:00:00-05:002018-07-30T01:00:00-05:00https://blog.francoisfaubert.com/2018/07/30/im-loving-dotnet-core<p>I’ve been a web programmer all my professional life. Though I learned Java in school, I see now that I’ve always worked with languages which have the lowest level of entry.</p>
<p>This means I’m really good with Javascript and PHP, as they have arguably been the easiest languages to use for web development over the last decade and a half.</p>
<p>For developing anything server-side, PHP has always suited my needs. Great packages can be found all over Composer’s repository like the ones by the <a href="https://thephpleague.com/">PHP league</a> and, especially, the elegant <a href="https://symfony.com/components">Symfony components</a>.</p>
<p>There are also powerful web frameworks written in PHP. I definitely feel <a href="https://laravel.com/">Laravel</a> stands out as one of the best across the whole programming landscape in that regard.</p>
<p>I never felt like I was missing out on anything and generally thought I was happy with my experiences. That was until recently when I did my first .NET Core application.</p>
<p>Now I don’t want to be a PHP developer at all.</p>
<h2 id="c-and-net-core">C# and .NET Core</h2>
<p>Fear not, I’m not turning this into a <a href="https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/">tirade of PHP criticism</a>. I still think PHP definitely can do web development well.</p>
<p>What I am trying to express here is that .NET Core and C# are raising my general enjoyment when working on code for any given similar application. They, directly and indirectly, make my life easier as a developer. Once you get a taste for that level of comfort, it’s hard to go back.</p>
<p>Right away when working on my first .NET Core project I was confronted by a couple of things I could never have in PHP:</p>
<h3 id="c-a-consistent-typed-language">C#: a consistent, typed language</h3>
<p>Coming from a loosely typed language, you may think typed languages can get tiresome. Even newer languages like Ruby and Python are loosely typed. I didn’t really think you’d need it at all before.</p>
<p>Certainly, when writing C# code, object typing can feel quite verbose. The thing is, in the <em>context of work</em>, when you have the pressure of quickly figuring out and permanently fixing bugs without necessarily knowing the whole application context, types are a true gift to the programmer.</p>
<p>As an added bonus, I’ve noticed that being forced to use strong typing naturally improves the code I write. It’s not that I couldn’t have been able to write the same thing in PHP, it’s that I probably wouldn’t have.</p>
<p>For instance, there would likely have been logical decisions done by comparing strings in a PHP approach instead of doing an isolation similar to Enums. String comparison is often a flimsy way of building application-central logic upon, but you don’t really have simple alternatives in PHP 7.</p>
<p>Pair that with <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/">Generics</a> and <a href="http://csharpindepth.com/articles/general/overloading.aspx">parameter overloads</a> and you can write some really pretty code.</p>
<h4 id="consistency">Consistency</h4>
<p>Native PHP methods are not consistent. Even after all these years, I never seem to remember them perfectly when using <code class="highlighter-rouge">array_filter($input, $callback)</code> versus <code class="highlighter-rouge">array_map($callback, $input)</code> or <code class="highlighter-rouge">strpos($haystack, $needle)</code> versus <code class="highlighter-rouge">array_search($needle, $haystack)</code>.</p>
<p>You shouldn’t have to remember all these quirks when programming. They distract you from your application’s code. There are none of these variations within the .NET Framework in C#.</p>
<p>Oh, I’m not kidding myself, I’m sure there are consistency issues in .NET Framework as well, but at least you have to dig a little more to find them.</p>
<p>The type methods are also correctly packaged under a meaningful group. I guess it helped to have access to namespaces all along. No need to prefix global methods with <code class="highlighter-rouge">array_</code> when the variable’s type infers it. This cleans up the language API quite a bit.</p>
<h4 id="better-native-objects-like-list">Better native objects, like List<></h4>
<p>In comparison, I also think there are missing core object types PHP. Arrays are used to represent all types of things, but there are not semantically meaningful.</p>
<p>As an example, Laravel and Symfony return custom-made collection objects around database query results to allow re-filtering and ease any further data management. You may argue that these list types with value-added should have been made available by now by default in PHP, even without type enforcement inside the object.</p>
<p>We’d likely see a performance gain if, for instance, Laravel’s implementation of <code class="highlighter-rouge">collect()</code> was running in C rather than in the interpreted PHP version.</p>
<p>There are multiple kinds of enumeration types in C#. Additionally, the <code class="highlighter-rouge">IEnumerable</code> interface grants the use of <a href="https://msdn.microsoft.com/en-us/library/bb308959.aspx?f=255&MSPPError=-2147217396">Linq</a> on these lists. It’s a descriptive way of doing operations on list objects that I think help express developer intent as opposed to a <code class="highlighter-rouge">foreach</code> loop on an Array.</p>
<p>This snippet from the official Linq documentation performs two sorts one after the other.</p>
<figure class="highlight"><pre><code class="language-c#" data-lang="c#"><span class="kt">string</span><span class="p">[]</span> <span class="n">names</span> <span class="p">=</span> <span class="p">{</span> <span class="s">"Burke"</span><span class="p">,</span> <span class="s">"Connor"</span><span class="p">,</span> <span class="s">"Frank"</span><span class="p">,</span> <span class="s">"Everett"</span><span class="p">,</span>
<span class="s">"Albert"</span><span class="p">,</span> <span class="s">"George"</span><span class="p">,</span> <span class="s">"Harris"</span><span class="p">,</span> <span class="s">"David"</span> <span class="p">};</span>
<span class="kt">var</span> <span class="n">s1</span> <span class="p">=</span> <span class="n">names</span><span class="p">.</span><span class="nf">OrderBy</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span> <span class="n">s</span><span class="p">.</span><span class="n">Length</span><span class="p">).</span><span class="nf">ThenBy</span><span class="p">(</span><span class="n">s</span> <span class="p">=></span> <span class="n">s</span><span class="p">);</span></code></pre></figure>
<h3 id="the-tools">The tools</h3>
<h4 id="not-many-changes-for-me">Not many changes for me</h4>
<p>I know I would rather use Linux servers over Windows and use Postgres or MySql over Microsoft’s SQL Server.</p>
<p>Unlike the previous Windows-only version of the .NET Framework (ASPNET), Core can be configured to connect to anything and runs on most OSes. It is in fact encouraged by how easy it is to configure how to start up a project.</p>
<p>That’s an important factor because I am not interested in changing everything I do.</p>
<h4 id="ides">IDEs</h4>
<p>PHPStorm and a correctly configured Visual Studio Code can act as a good IDEs for developing PHP. You get decent code completion in most cases. You can quickly see it never gets completely integrated though.</p>
<p>You need <a href="https://github.com/barryvdh/laravel-ide-helper">a helper library</a> and custom code changes in your application to get autocompletion in a Laravel project. It doesn’t feel right. Shouldn’t my editor be able to figure out a lot more by itself now that we have been sending robots on Mars for a while now?</p>
<p>I would think that not having to pre-compile all your code prevents the editor from finding out all the project’s namespaces and classes as Roselin does for C#. Compiling probably grants better code reflexion for the editor and that is harder to crawl in PHP.</p>
<p>Though I still enjoy coding in Visual Studio Code better (because of window management and shortcuts mainly), Visual Studio proper is a beast of an IDE. The refactors it can do and the things it knows about your application is downright impressive when you have not been exposed to that beforehand.</p>
<p>The C# debugger is also very powerful, allowing you to jump back an forth in execution unlike anything I have experienced in XDebug.</p>
<h2 id="not-everyones-happy">Not everyone’s happy</h2>
<p>I work with a cranky developer that has been using the classic .NET Framework implementation throughout all his career. He knows historical facts and has been through many language debates over the years.</p>
<p>He’s quite disappointed with how the .NET Core implementation has begun and mentions it absolutely does not compare with the Windows’ only version of .NET Framework.</p>
<p>Apart from how the project was managed at the beginning, his main gripes seem to revolve around having to explicitly configure how things talk to each other in Core. IIS and the .NET Framework seem to have been really tightly integrated inthe past and the lines where they talked to each other seem to blur when I listen to him describe it. There’s none of that plug and play architecture in the cross platform .NET Core implementation.</p>I’ve been a web programmer all my professional life. Though I learned Java in school, I see now that I’ve always worked with languages which have the lowest level of entry.How to build a staging server with Docker, Jenkins and Traefik2018-06-11T01:00:00-05:002018-06-11T01:00:00-05:00https://blog.francoisfaubert.com/2018/06/11/dockerized-jenkins-with-traefik<p><strong>This guide is largely outdated at this point. You should instead consider installing <a href="https://www.jenkins.io/doc/book/installing/kubernetes/">Jenkins on Kubernetes with Helm</a>.</strong></p>
<p>This first page of the guide is dedicated to explaining the rationale behind this setup. You may <a href="/2018/06/11/dockerized-jenkins-with-traefik-2.html">skip ahead</a> to the actual implementation if you don’t need this information.</p>
<h2 id="background">Background</h2>
<p>Over the past months, I have been promoting <a href="https://en.wikipedia.org/wiki/DevOps">DevOps</a> culture at <a href="https://mutation.io/">Mutation</a>. For some time now, our projects have both been built and distributed using <a href="https://deploybot.com/">Deploybot</a>’s platform. While it worked reasonably well enough to get us going at the beginning, we outgrew Deploybot as our projects gained in complexity.</p>
<p>One of the possibilities I felt we were particularly missing out on was to fully leverage Docker during both the build and the deployment process. Our projects usually use one of the .Net and PHP stacks and it is not necessarily practical to have different staging environments for each technology.</p>
<p>Additionally, configuring staging environments had to be done manually and we have been stepping on each other’s toes when multiple developers worked on the same project but tried to preview different feature branches alongside the master branch, simultaneously.</p>
<p>We decided to rework our development and staging pipelines to improve on some of our current pain points. At this point, however, we are not ready internally to also distribute Docker images in production. This guide will also stop short of doing so.</p>
<h2 id="requirements-of-the-desired-stack">Requirements of the desired stack</h2>
<p>I have compiled a list of requirements this reworked stack should feature for it to be worth the trouble :</p>
<ul>
<li>Projects must be able to configure how they are to be built, tested and distributed from a file in version control.</li>
<li>Projects must handle their code <em>and</em> server dependencies from a file in version control.</li>
<li>The stack needs to be OS and language agnostic.</li>
<li>Our Docker registry must be private.</li>
<li>Each branch must be able to be previewed in its own staged version. This must be automated.</li>
<li>We must enforce secure <code class="highlighter-rouge">https</code> URLs.</li>
<li>The environments must whitelist IPs and deny others.</li>
<li>The whole solution must remain economic.</li>
</ul>
<h2 id="proposed-solution">Proposed solution</h2>
<p>After looking into various possibilities, I have settled on a combination of Docker, Jenkins, Portainer, and Traefik working hand-in-hand as answers the requirements. These services will all be running inside containers on a Linux host.</p>
<h3 id="docker">Docker</h3>
<p>It feels elegant to only have <a href="https://www.docker.com/">Docker</a> installed on the host server. We can kickstart other tools as services within Docker containers instead of installing them on the host server directly.</p>
<p>I will be creating a Docker Swarm even though we do not intend to use load balancing. Stacks will be deployed through a <code class="highlighter-rouge">docker-compose</code> file tailored for the environment.</p>
<p>While you can use a free <a href="https://hub.docker.com/">public cloud</a> for storing custom Docker images, I will rather save our build snapshots in a custom, private, Docker Registry. I will use the official container to launch an instance of it.</p>
<h3 id="jenkins">Jenkins</h3>
<p><a href="https://jenkins.io/">This open source automation server</a> will be used to run the different tasks required by the builds. Though I could have used a cloud-based solution, hosting our own continuous integration server on premise made more sense for our general use case.</p>
<p>For the time being, Jenkins is not very pretty, but the advent of <a href="https://jenkins.io/projects/blueocean/">Blue Ocean</a> improved the user experience and how <a href="https://jenkins.io/doc/book/pipeline/">build pipelines</a> are configured.</p>
<h3 id="traefik">Traefik</h3>
<p>We don’t really want to open more ports than we have to on the host server. We only want – and a web server should only generally need – to open ports <code class="highlighter-rouge">22</code>, <code class="highlighter-rouge">80</code> and <code class="highlighter-rouge">443</code>.</p>
<p>Our Docker containers will potentially fight for the same ports as they are brought up. Your websites containers will probably all want port <code class="highlighter-rouge">80</code> or <code class="highlighter-rouge">443</code>. We need a reverse-proxy in front of the containers that will route traffic to the correct destinations based on DNS information. The proxy will know to go from port <code class="highlighter-rouge">80</code>/<code class="highlighter-rouge">443</code> to whatever the dynamic IP of the target container ends up being.</p>
<p><a href="https://traefik.io/">Traefik</a> is a fast reverse-proxy written in Go that is able to listen for Docker container events. It will know when containers are started or stopped, and will automatically add or remove their DNS rewrites accordingly. It uses custom Docker labels to send key/values pairs back to it’s proxy, then used to customize the desired configuration for each container.</p>
<p>Additionally, the proxy supports automated handling of <a href="https://letsencrypt.org/">Let’s Encrypt</a> certificates out of the box. This will allow our environments to run under <code class="highlighter-rouge">https</code> very easily. There are <a href="https://letsencrypt.org/docs/rate-limits/">rate limits</a> on certificate generation, but you should not hit them for a long time.</p>
<h3 id="portainer">Portainer</h3>
<p>Developers will need to quickly find details about the running containers. I think it is impractical to force them into <code class="highlighter-rouge">ssh</code>-ing onto the server and <code class="highlighter-rouge">docker inspect</code> through containers to extract a database IP, for instance.</p>
<p><a href="https://portainer.io/">Portainer</a> offers a simple but feature-rich UI that allows management of your Docker containers and is exactly what I need to get people excited about containerization.</p>
<h2 id="really-meant-for-a-staging-environment">Really meant for a staging environment</h2>
<p>The proposed stack is meant for an internal use inside a company. It should be protected from the Internet by firewalls and other appropriate measures.</p>
<p>You should not use the information in this guide for constructing a production stack. The steps illustrated here will do not necessarily follow best security practices. Certainly, assumptions are made in the way things are configured that would be false in a production environment.</p>
<p>Now that you know why this is what I am building, it is time to get our hands dirty and begin <a href="/2018/06/11/dockerized-jenkins-with-traefik-2.html">preparing the server</a>.</p>This guide is largely outdated at this point. You should instead consider installing Jenkins on Kubernetes with Helm.Tip of the hat to Digital Ocean2018-01-19T00:00:00-06:002018-01-19T00:00:00-06:00https://blog.francoisfaubert.com/2018/01/19/tip-of-the-hat-digital-ocean<p>This week, I woke up to this nice surprise in my inbox:</p>
<p><img src="/assets/imgs/blogs/thanks-digital-ocean.png" alt="Thanks, Digital Ocean!" />
<em>Thanks, Digital Ocean!</em></p>
<p>For the purpose of messing around, but also for hosting the currently incomplete <a href="https://themusictank.com">The Music Tank</a>, I have been keeping a cheapest <a href="https://www.digitalocean.com/">Digital Ocean</a> droplet online for some time now. At 5$ a month, I have a Linux box that fully satisfied my needs.</p>
<p>The surprise is that starting this week, for the same price, Digital Ocean has increased my machine’s RAM from 512MB to 1G and raised my SSD disk size from 20GB to 25GB. And it turns out the RAM boost is absolutely a noticeable change.</p>
<p>The reason I feel this deserves a blog post is that my account was boosted for free, without any action on my part.</p>
<p>That is the exact opposite of what both my cell phone carrier and Internet provider are doing. I’ve been a customer of theirs for years and their offerings have changed multiple times since I’ve joined. However, for my account to get upgraded to their new ground-level plans, I would have to phone in and complain about it while throwing threats of leaving for their competitors.</p>
<p>I find this is a pathetic way of doing business. It effectively means they punish good payers and silent customers while giving tributes to the loudmouths.</p>
<p>One would think that it’s cheaper for an enterprise to automatically upgrade their customers as their service offering changes in time. I can’t picture managing hundreds of plans simultaneously, a good subset of these being invalid for new sales, being efficient. At the very least, I’m sure it can’t be simple.</p>
<p>I am happy to see that is not the case with my cloud hosting provider.</p>
<p>If you are not a Digital Ocean customer and would like to set up an account, you may use <a href="https://m.do.co/c/a8792f44bd04">my referral link</a> which will give you a 10$ credit. But you don’t have to, it’s not the point of the post.</p>This week, I woke up to this nice surprise in my inbox:Please complain correctly2018-01-10T00:00:00-06:002018-01-10T00:00:00-06:00https://blog.francoisfaubert.com/2018/01/10/please-complain-correctly<p>As of late, I have been learning how to reconfigure and port my web-based projects over to Docker developing on a Windows machine.</p>
<p>This journey, which is still not over, brought me along frustrating dead ends, to poorly documented blog posts, and gave me elating epiphanies when they finally deign come.</p>
<p>This post is not about that journey.</p>
<p>While I was reading around, thoroughly digging for articles explaining ways of installing Docker on Windows or describing the infamously <a href="https://github.com/hashicorp/vagrant/issues/5844">broken symlinks inside Vagrant synced folders</a>, I found many articles to have an unnecessary anti-Microsoft bias.</p>
<p>To dismiss Windows as a development platform while implying that the best development platform runs on Apple is shortsighted in most cases.</p>
<h2 id="i-dont-care-for-that-debate">I don’t care for that debate</h2>
<p>I do not intend to argue against Apple doing quality high-end products, nor do I want to say Microsoft is any better or worse. They are both good, with strong points and griping flaws here and there.</p>
<p>I feel the differences tend to balance out in the end. Because both alternatives are different tools, it’s also OK to prefer one over the other for varying reasons whether they are technical or sentimental.</p>
<p>Choosing between Mac and Windows is also the most irrelevant choice you can make for web development.</p>
<p>The real issue – the one I keep batting my head on during my Docker journey – does not come from me having to use Windows. The issue is trying to make Linux tools work on another platform.</p>
<h2 id="modern--developer-centric">Modern = developer centric</h2>
<p>Apple and Microsoft are both very modern in the way they build their solutions nowadays. We can even throw Facebook, Google, and Amazon in that basket. Every single one of these successful companies is – or has been forced into becoming – developer-centric. They all want developers to use their products as much as they want to attract regular consumers.</p>
<p>Part of this means that all these companies are pushing for technology stacks they built for their proposed environment and constantly improve their stack in that loop.</p>
<p>Everybody old enough probably remembers this video:</p>
<iframe src="https://www.youtube.com/embed/V-FkalybggA" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>
<p>That was an important moment for Microsoft because Steve Ballmer was, at the time, leading a shift in ideology that placed developers at the core of most of the corporation’s products. It is not by mistake that <a href="https://www.netmarketshare.com/operating-system-market-share.aspx?options=%7B%22filter%22%3A%7B%22%24and%22%3A%5B%7B%22deviceType%22%3A%7B%22%24in%22%3A%5B%22Desktop%2Flaptop%22%5D%7D%7D%5D%7D%2C%22dateLabel%22%3A%22Trend%22%2C%22attributes%22%3A%22share%22%2C%22group%22%3A%22platform%22%2C%22sort%22%3A%7B%22share%22%3A-1%7D%2C%22id%22%3A%22platformsDesktop%22%2C%22dateInterval%22%3A%22Monthly%22%2C%22dateStart%22%3A%222017-01%22%2C%22dateEnd%22%3A%222017-12%22%2C%22plotKeys%22%3A%5B%7B%22platform%22%3A%22Windows%22%7D%2C%7B%22platform%22%3A%22Mac%20OS%22%7D%5D%2C%22segments%22%3A%22-1000%22%7D">Microsoft is leading in adoption</a> and it is also not by coincidence that C# remains a real contender to Java.</p>
<p>To me, a similar moment happened at Apple when Steve Jobs decided to <a href="https://www.apple.com/hotnews/thoughts-on-flash/">ship iPhones without Flash support</a>. In doing so while rapidly improving Webkit/Safari, I would say the company singlehandedly bullied the Internet into standardizing. The result is a much more friendly and consistent playground for web developers. It has also become developer-centric.</p>
<h2 id="the-right-tool-for-the-stack">The right tool for the stack</h2>
<p>It should come as no surprise that building a <a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP stack</a> on something else than a Linux machine may cause hiccups.</p>
<p>For instance, if I were doing C# projects on top of IIS and SQL Server, everything would pretty much be plug and play on Windows because that is the stack they support best.</p>
<p>I too think many web libraries are often easier to install on MacOS compared to doing so on Windows. However, I feel that has a lot more to do with Mac <a href="https://upload.wikimedia.org/wikipedia/commons/5/50/Unix_history-simple.png">coming from Unix</a>, a common ancestor also shared by Linux, rather than philosophical ongoing choices made by the corporation.</p>
<h2 id="whats-in-production">What’s in production?</h2>
<p>If you really want to get into an argument over the best OS for web development, anything short of Debian would be a poor choice.</p>
<p>Knowing the final production server is going to be a Linux box, and knowing the tools I want to use are really only natively supported by Linux, is it really logical to develop on another platform?</p>
<p>A Linux desktop may not be extra practical for some, but it would certainly be an efficient environment.</p>
<h2 id="virtualization-to-end-this">Virtualization to end this</h2>
<p>For the reasons mentioned above, I am using Vagrant or Docker to pull a Linux box on which all server operations are made (or anything server-side really). That way my application runs on its native stack and I sidestep everything. My host computer can run on whatever it wants and it doesn’t matter.</p>
<p>That it “doesn’t matter” is really important. Web applications and their server libraries should not care about how they behave on anything but their intended production environment. Similarly, your host OS should not go out of its way to support libraries that don’t have compatible APIs.</p>
<p>When virtualizing your requirements, the hard job of harmonizing the conversation between these APIs become the virtualization driver’s responsibility. It also happens it is what it was tailored to be doing.</p>
<p>It is unfair for both OSes and vendors to be expected to build flawless experiences on every platform when that is not their core focus.</p>
<p>We surely can complain when things don’t work so well so long as we are complaining about the correct problem.</p>As of late, I have been learning how to reconfigure and port my web-based projects over to Docker developing on a Windows machine.CSS: Tell, don’t describe2017-12-20T00:00:00-06:002017-12-20T00:00:00-06:00https://blog.francoisfaubert.com/2017/12/20/css-tell-dont-describe<p>Writing an article which illustrates <a href="/2017/11/29/atomic-css.html">my take on Atomic CSS</a> helped me put words on how I feel CSS should be written and maintained.</p>
<p>My preferred method of writing styles is neither purely functional or component-based. The method I would like to propose is closer to how back-end code is handled.</p>
<p>There is an Object Oriented programming approach called <a href="https://martinfowler.com/bliki/TellDontAsk.html">Tell don’t ask</a>. At its core it can be surmised as follows:</p>
<blockquote>
<p>Rather than asking an object for data and acting on that data, we should instead tell an object what to do.</p>
</blockquote>
<p>It is a simple principle that has big implications while writing object classes. Using this method, you tend to generate objects that encapsulate their internal logic while exposing their intent as public methods. Objects with fewer getters may be harder to manipulate in unintended ways.</p>
<p>Personally, this approach helps me apply the <a href="https://en.wikipedia.org/wiki/Single_responsibility_principle">Single responsibility principle</a> by limiting public access to object data. I, therefore, tend to make multiple objects that each does one different thing instead of overusing <code class="highlighter-rouge">getXYZ()</code> methods from a god class that does multiple different manipulations.</p>
<h2 id="applying-it-to-css">Applying it to CSS</h2>
<p>I find the Tell don’t ask method to be an elegant way of writing CSS as well. The implementation of that method results in a variation of <a href="https://en.wikipedia.org/wiki/Trait_(computer_programming)">Trait sharing</a> applied to DOM elements.</p>
<p>I propose to call this behavior-centric methodology “<strong>Tell, don’t describe</strong>”.</p>
<p>I would define it as :</p>
<blockquote>
<p>Rather than describing how an object should look, we should instead tell an object what it should do.</p>
</blockquote>
<h2 id="what-i-am-trying-to-achieve">What I am trying to achieve</h2>
<p>To clarify the points I am trying to improve with this method, I have taken screenshots from projects that I have come across. These examples are <em>real</em> in the sense that competent people have written it in the context of employment.</p>
<p>My goal is not to say there is a problem with the developers themselves, but rather to suggest that maybe the approach they have used to write their styles allowed for <a href="https://en.wikipedia.org/wiki/Code_smell">smells</a> to occur too easily.</p>
<h3 id="goals">Goals:</h3>
<p><strong>Prevent deep component styles</strong></p>
<p><img src="/assets/imgs/blogs/deep-component-styles2.png" alt="Deep in the rabbit hole" />
<em>Deep in the rabbit hole</em></p>
<p>Because you are coupling the HTML hierarchy inside the style rules, you may have to deal with selectors that suddenly disconnect, or which lose specificity as the HTML source changes.</p>
<p>We want to be able to modify the views without breaking the styles as much as we can.</p>
<p>We also want to discourage adding new edge case in the existing component styles and make it harder for a developer to decide to create a copy of the component styles that would only manage the extra HTML tags.</p>
<p><strong>Optimize file sizes</strong></p>
<p><img src="/assets/imgs/blogs/css-filesize.png" alt="Even Webpack thinks this is huge" />
<em>Even Webpack thinks this is huge</em></p>
<p>Unless you spend a very large amount of your time actively refactoring and regrouping code to optimize reuse in an ongoing project, and unless you maintain a thorough grasp of the full code base in your mind at all times, you will end up with many duplicate style concepts in your files.</p>
<p>Sometimes, you may not be able to completely extract common assignments between styles because their varying children DOM elements may depend on common top-level assignments.</p>
<p>We want to make style assignments cascade at an HTML element level to decouple the styles from the children HTML tags as much as we can.</p>
<p>We would rather leverage natural style inheritance through the <code class="highlighter-rouge">class</code> attribute rather than import style mixins in order for us to maintain few complex selector chains and juggle fewer overrides at during style declarations.</p>
<p><strong>Obvious intentions</strong></p>
<p><img src="/assets/imgs/blogs/hard-to-convey-intention.png" alt="I don't know how you look" />
<em>I don’t know how you look</em></p>
<p>It is hard to modify existing template code if you do not have good chunks of the project’s CSS in mind when looking at its HTML. It is not a realistic expectation to think developers on maintenance duty will completely ingest a project’s personalized differences at a glance before working on their issue.</p>
<p>We want to be able to understand the visual intentions of template elements by looking at the least possible number of files possible.</p>
<h2 id="what-happens-when-you-inject-behavior">What happens when you inject behavior</h2>
<p>One can solve the issues raised previously by attaching behavior to HTML elements instead of describing them. CSS then becomes a collection of simpler visual behaviors that you can grant, deny or chain as CSS class names. It is irrelevant whether you use pre or post processors to do so.</p>
<p>From font sizes and margins to animations and colors palettes, everything can be described as a reusable behavior. The following HTML, even if you do not know how the CSS is built, clearly denotes its visual intentions:</p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="nt"><div</span> <span class="na">class=</span><span class="s">"about-us-cta horizontal-children alternate-font light-margin show-hint-on-hover"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"hidden hint"</span><span class="nt">></span>I will display when you hover my parent<span class="nt"></div></span>
<span class="nt"><div></span>Lorem ipsum<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"centered-horizontally takes-half-width"</span><span class="nt">></span>Lorem ipsum<span class="nt"></div></span>
<span class="nt"></div></span></code></pre></figure>
<p>Of course – if it is still required at all after applying common behavioral styles – you may then apply edge cases on a custom selector (<code class="highlighter-rouge">.about-us-cta</code> in this example). The custom rules will be much simpler and less lengthy because there is nothing really left to modify that hasn’t been described by the behavioral assignation. Such differences may even be bounced back to the design team as possible inconsistencies in their work.</p>
<p>In most cases, you can reuse common behaviors across components that have no direct relations to each other by assigning the common behavior classes.</p>
<p>In order words, though the <code class="highlighter-rouge">.houses</code> and <code class="highlighter-rouge">.cars</code> classes may both contain <code class="highlighter-rouge">.windows</code> (or to give a more CSS-oriented example, may have a similar <code class="highlighter-rouge">border</code> treatment), it may still not make sense for the two concepts to be grouped under a common style named <code class="highlighter-rouge">.all-things-with-windows</code>.</p>
<p>Grouping the two slightly different concepts under the same parent may influence developers in adding <code class="highlighter-rouge">.wheels</code>-related assignments (maybe different <code class="highlighter-rouge">margins</code>) within that common group. These would have no visual impact for <code class="highlighter-rouge">.houses</code> but their use-case would still have to be taken into account when modifying the styles.</p>
<p>It may be more useful to create a <code class="highlighter-rouge">.has-windows</code> behavior that minds its own business and can be graphed to any other context, like <code class="highlighter-rouge">.has-wheels</code>. You would end up with an HTML element defined as <code class="highlighter-rouge"><div class="has-windows has-wheels">Lorem ipsum</div></code> and the CSS declaration of these two classes would not be intertwined.</p>
<p>That is what I feel is the core strength of behavioral CSS. By defining clear and unchanging behaviors you greatly limit selector depth in the style declaration. It allows you to pick and chose behaviors to add to any DOM element.</p>
<p>Because the behavior does not attempt to handle deep elements (or at least tries very hard not to), you should not have to override styles on descendant elements. Since you don’t have to care which styles may or may not have been defined by an ancestor, you can attach behavior to these other elements as well and similarly continue down the DOM tree.</p>
<p>In a chain of behavioral class names, the intention of the element becomes obvious because it is explicitly set in the HTML. By glancing at the source file you get a quick idea of what that block of HTML is <em>doing visually</em>. Adding or removing behaviors can be estimated easily by glancing at the assignment chain.</p>
<p>In this context, it seems reasonable to expect developers to remember a limited array of repeated visual concepts within a project. They could even be able to change the visual behavior of elements only by modifying template files.</p>
<h2 id="this-is-not-functional-css">This is not functional CSS</h2>
<p>You cannot describe this approach as being “Atomic” or “Functional”. The goal here is to code explicit behaviors for a project and not to generate a list of tools that map styles – often one-for-one – to be peppered in the HTML file.</p>
<p>In this behavioral minded method of writing CSS, it is more important to encapsulate the meaning of <em>what it does</em> rather than to encapsulate whether it is aligned using flex or floats. It is important to see that the ways styles are defined within a behavior class do not matter as long as the exposed visual results remain the same.</p>
<p>In that way, it is more important to <em>tell</em> elements what to do rather than to <em>describe</em> them.</p>Writing an article which illustrates my take on Atomic CSS helped me put words on how I feel CSS should be written and maintained.How to: using Docker Toolbox as Visual Studio Code CLI2017-12-14T00:00:00-06:002017-12-14T00:00:00-06:00https://blog.francoisfaubert.com/2017/12/14/docker-toolbox-as-visual-studio-code-cli<p>For the last 4 months, I have used <a href="https://www.docker.com/">Docker</a> in my application development setup for everything but .NET projects. Though I would not call the transition smooth and seamless, I now have all my required services running as Docker containers.</p>
<p><a href="https://blog.philipphauer.de/discussing-docker-pros-and-cons/">One of the advantages</a> of doing so it that one can manage server dependencies in parallel with code dependencies within a project. You can, therefore, ensure your app bundles a Docker image that contains what it needs to run correctly from a server standpoint.</p>
<p>On a local development environment, I like using Docker because it keeps my host PC free of software I don’t necessarily want running all the time. Because of Docker I no longer need to install HTTP server(s), programming language(s), and database(s) on my host computer. I can easily switch technologies, or versions of a technology or service by requesting another Docker image.</p>
<p>I find this pattern more elegant than installing multiple versions of PHP side by side, than playing with port configurations because IIS and Apache both fight for port 80 or than having a full-fledged virtual machine for each possibility.</p>
<h3 id="docker-toolbox-the-poor-mans-version">Docker Toolbox, the poor man’s version</h3>
<p>You cannot install Docker on Windows unless you own Windows 10 Professional or Enterprise 64-bit, both of which ship with <a href="https://docs.docker.com/docker-for-windows/troubleshoot/#hyper-v">Hyper-V</a> enabled.</p>
<p>Other folks like us poor souls must use <a href="https://docs.docker.com/toolbox/toolbox_install_windows/">Docker Toolbox</a> as an alternative. It goes around the Hyper-V problem by running Docker within a virtual Linux machine. It is on this machine’s IP that you will connect instead of the usual <code class="highlighter-rouge">localhost</code>. This may seem a convoluted setup, but it makes a lot of sense in practice.</p>
<h3 id="one-cli-to-run-it-all">One CLI to run it all</h3>
<p>Docker Toolbox ships with its own CLI executable. It is explicitly configured with the correct environment variables and is kicked off with a boot script in order to pre-configure it so that when you type commands such as <code class="highlighter-rouge">docker</code> and <code class="highlighter-rouge">docker-compose</code> the CLI knows what you are referencing to.</p>
<p>Unfortunately, these settings do not apply to Powershell or any other CLI you may have installed on your computer. Visual Studio Code’s integrated CLI being an instance of Powershell, you cannot use Docker commands within the integrated terminal.</p>
<p><img src="/assets/imgs/blogs/vs-cli-docker.png" alt="You cannot use Docker commands in Powershell" />
<em>You cannot use Docker commands in Powershell</em></p>
<p>Let’s see how we can improve the integration of Toolbox within Visual Studio Code.</p>
<h2 id="configuring-visual-studio-code">Configuring Visual Studio Code</h2>
<p>VS Code is quite flexible and it allows you to switch the type of integrated terminal it uses. We will replace the default Powershell with the CLI bundled with Docker Toolbox.</p>
<p>Open your user settings by going through the menu or by pressing <code class="highlighter-rouge">ctrl + ,</code>. Assuming Docker Toolbox is installed at its default location, add the following settings to the file :</p>
<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
</span><span class="nl">"terminal.integrated.shell.windows"</span><span class="p">:</span><span class="w"> </span><span class="s2">"C:</span><span class="se">\\</span><span class="s2">Program Files</span><span class="se">\\</span><span class="s2">Git</span><span class="se">\\</span><span class="s2">bin</span><span class="se">\\</span><span class="s2">bash.exe"</span><span class="p">,</span><span class="w">
</span><span class="nl">"terminal.integrated.cwd"</span><span class="p">:</span><span class="w"> </span><span class="s2">"C:</span><span class="se">\\</span><span class="s2">Program Files</span><span class="se">\\</span><span class="s2">Docker Toolbox"</span><span class="p">,</span><span class="w">
</span><span class="nl">"terminal.integrated.shellArgs.windows"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"--login"</span><span class="p">,</span><span class="w"> </span><span class="s2">"-i"</span><span class="p">,</span><span class="w"> </span><span class="s2">"C:</span><span class="se">\\</span><span class="s2">Program Files</span><span class="se">\\</span><span class="s2">Docker Toolbox</span><span class="se">\\</span><span class="s2">start.sh"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>What this does is it sets the default terminal to the one shipped with Git, changes the starting directory to Toolbox’s, and it executes the bootstrap script that is usually automatically called by opening the <code class="highlighter-rouge">Docker Quickstart Terminal</code> shortcut.</p>
<p><img src="/assets/imgs/blogs/vs-cli-docker-booted.png" alt="Docker Toolbox is correctly launched" />
<em>Docker Toolbox is correctly launched</em></p>
<h2 id="not-quite-a-celebration">Not quite a celebration</h2>
<p>There is one major flaw in this setup that I have not been able to resolve at the moment: take note the directory you end up being loaded in. Instead of booting in the context of the current project’s root directory, you will start your session in your home directory each time.</p>
<p>In theory, one may expect it would be possible to script the whole kickoff process in a custom shell script that eventually sets the current working directory after invoking Toolbox’s <code class="highlighter-rouge">start.sh</code>, but that’s just a theory for the moment.</p>
<p>If you happen to improve on this process, <a href="https://twitter.com/francoisfaubert">drop me a line</a>!</p>For the last 4 months, I have used Docker in my application development setup for everything but .NET projects. Though I would not call the transition smooth and seamless, I now have all my required services running as Docker containers.How to: configure PHP & NPM on Circle CI2017-12-08T00:00:00-06:002017-12-08T00:00:00-06:00https://blog.francoisfaubert.com/2017/12/08/configure-php-and-npm-on-circle-ci<p>Configuring your projects to use continuous integration (CI) and continuous distribution (CD) is a great way of ensuring their integrity from the moment you commit to the moment the projects make their ways to production.</p>
<p>There are free CI/CD services available for projects publically hosted on <a href="https://github.com">GitHub</a> or <a href="https://bitbucket.org">Bitbucket</a>. At the moment the most popular of these would likely be <a href="https://travis-ci.org/">Travis</a>. Travis is quick and easy to use and has been a good friend of open projects on GitHub for a long time now.</p>
<p>However, an alternative has been gaining ground recently in the form of <a href="https://circleci.com/">Circle CI</a>. With the release of the second version of their API, you may now build your projects on personalized Docker images using single configuration files that you add to your project’s repository.</p>
<p>In this article, we will be looking at how to fully configure the CI/CD process from start to finish of a PHP project which compiles it’s frontend assets using NPM. The PHP project type I will use will be a Laravel project and you will see custom commands for the framework in the end results. It should be relatively easy for you to replace or remove these lines if you use a different framework.</p>
<p>I write following the assumption you will be able to <a href="https://circleci.com/docs/2.0/first-steps/">connect your project’s repository to Circle CI</a> so that each time you push new code it correctly triggers a build. You may find additional information on building PHP projects in their <a href="https://circleci.com/docs/2.0/language-php/">official documentation</a> through they do not mention how to implement NPM.</p>
<p>A complete <code class="highlighter-rouge">circle.yml</code> example can be found at the end of the article.</p>
<h2 id="circleyml">circle.yml</h2>
<p>The first step is to create a file named <code class="highlighter-rouge">circle.yml</code> at the root of your project structure. In it, we will specify the Circle CI version so they can understand the format of the file on their end. You will also want to declare an image from the <a href="https://hub.docker.com/">Docker Hub</a> on which you will build the project.</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="m">2</span>
<span class="na">jobs</span><span class="pi">:</span>
<span class="na">build</span><span class="pi">:</span>
<span class="na">docker</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">image</span><span class="pi">:</span> <span class="s">misterio92/ci-php-node</span>
<span class="na">steps</span><span class="pi">:</span></code></pre></figure>
<p>This translates to “<em>Using the <strong>2</strong>nd version, your first <strong>job</strong> is to <strong>build</strong> a <strong>docker image</strong> using the following <strong>steps</strong></em>”. This version of the configuration API is really easy to read and understand as you can see.</p>
<p>I am suggesting you use <code class="highlighter-rouge">misterio92/ci-php-node</code> as Docker image because it is small and it comes will all we require already installed. As it is already fully bundled, Circle CI will pull and run it quickly and will <a href="https://thenewstack.io/understanding-the-docker-cache-for-faster-builds/">likely cache bits of it</a> to speed up the next run even further.</p>
<p>Know that there are many Docker images you can choose from to execute the build, however. You may even choose to use your own pre-built or dynamically add to a <a href="https://hub.docker.com/_/php/">lightweight Alpine build of PHP</a> and install NPM and other dependencies at run time using <code class="highlighter-rouge">apt-get</code>.</p>
<h2 id="setting-up-steps">Setting up steps</h2>
<p>Next up is to write the list of steps that need to be performed to build and deploy the project.</p>
<p>In this block, it is important to leverage Circle CI’s <a href="https://circleci.com/docs/2.0/caching/">caching mechanism</a> to ensure fast build execution. In a classic PHP project, the two big things that you should cache are the <code class="highlighter-rouge">vendor</code> packages from Composer as well as the <code class="highlighter-rouge">node_modules</code> from NPM. Having these two folders cached will prevent unnecessary file downloads if the dependencies are still valid from one build to the next. Hitting the cache instead of downloading them anew will grant massive performance gains.</p>
<p>In chronological order, the steps required to build a project using PHP and NPM could look like :</p>
<ol>
<li>Check out the project files</li>
<li>Restore the file caches</li>
<li>Install Composer dependencies</li>
<li>Install NPM dependencies</li>
<li>Save the updated file caches</li>
<li>Build the assets</li>
<li>Run unit tests</li>
</ol>
<p>Transposed in Circle CI configuration, these steps would look like :</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"> <span class="na">steps</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">checkout</span>
<span class="pi">-</span> <span class="na">restore_cache</span><span class="pi">:</span>
<span class="na">keys</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">composer-cache-{{ checksum "composer.json" }}</span>
<span class="pi">-</span> <span class="s">composer-cache-</span>
<span class="pi">-</span> <span class="s">dependency-cache-{{ checksum "package.json" }}</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Installing PHP packages</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">composer install -n --prefer-dist --ignore-platform-reqs --optimize-autoloader</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Installing NPM packages</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">npm install</span>
<span class="pi">-</span> <span class="na">save_cache</span><span class="pi">:</span>
<span class="na">key</span><span class="pi">:</span> <span class="s">composer-cache-{{ checksum "composer.json" }}</span>
<span class="na">paths</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">vendor</span>
<span class="pi">-</span> <span class="na">save_cache</span><span class="pi">:</span>
<span class="na">key</span><span class="pi">:</span> <span class="s">dependency-cache-{{ checksum "package.json" }}</span>
<span class="na">paths</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">./node_modules</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Building production package</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">npm run production</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Unit tests</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">vendor/bin/phpunit</span></code></pre></figure>
<p>These new lines will allow the build to download all the project’s dependencies, to cache them at the current version using a unique checksum of the dependency manager’s JSON file, to build the assets and finally to check whether our unit tests are still passing.</p>
<p>If anything goes wrong or if something unexpected occurs during that process, the build will fail and stop at the point of the error. It’s important to see the step that runs PHPUnit as your last safeguard before the commit is deployed.</p>
<h2 id="deployment">Deployment</h2>
<p>Assuming the build has reached this point you may now allow Circle CI to deploy the build to a server. I guess there are multiple schools of thought on how to do that, but I will propose my preferred way of doing it.</p>
<h3 id="you-will-need">You will need</h3>
<p>You will need to <a href="https://serversforhackers.com/c/permissions-and-user-management">create a user</a> that will be dedicated to deploying files on the server which the build will be uploaded. This user will need to have similar rights as your web host (Apache, Ngnix, etc) to ensure files can be read and written correctly. The deployer user will also need to have Circle CI’s public key <a href="http://www.linuxproblem.org/art_9.html">authorized on the server</a> so that you do not leave any passwords in your <code class="highlighter-rouge">circle.yml</code> file. The details on how to configure all of these steps are out of the scope of the article.</p>
<p>In this example, the user used for deployment will be called <code class="highlighter-rouge">circleci</code> and we will be deploying to <a href="https://themusictank.com">themusictank.com</a>, or <code class="highlighter-rouge">138.197.148.166</code>.</p>
<p>In chronological order, the detailed steps required to deploy the project could be :</p>
<ol>
<li>Tell the Docker image it should know the IP of the final server</li>
<li>Sync the files between the two</li>
<li>Execute command on the server to complete the deployment</li>
</ol>
<p>Translated in Circle CI steps, this would be:</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"> <span class="na">steps</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Add server keys</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">ssh-keyscan 138.197.148.166 >> ~/.ssh/known_hosts</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">rsync -avzp --delete --exclude-from '.rsyncignore' . circleci@138.197.148.166:/var/www/themusictank.com</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Post deploy</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">ssh circleci@138.197.148.166 "cd /var/www/themusictank.com && php artisan route:cache"</span></code></pre></figure>
<p>In the previous example note how I chose to keep the list of ignored files in the sync as a file called <code class="highlighter-rouge">.rsyncignore</code>. Because it’s just another file in the project, you can easily modify it as you go. Among the files and folders ignored are <a href="https://github.com/themusictank/themusictank.com/blob/3278fc6d3050d44ecb54bc45c121685e42f1b7fb/.rsyncignore">node_modules, tests, and git files</a></p>
<p>Finally, the deployer will connect through SSH to cache Laravel routes to speed up the website.</p>
<h2 id="end-result">End result</h2>
<p>Here is the full version of a <code class="highlighter-rouge">circle.yml</code> file you can use on PHP projects which compiles its frontend through NPM. An updated real-world example can be seen in <a href="https://github.com/themusictank/themusictank.com/blob/31235281be14f16c8b41472e36ef421c811527f1/circle.yml">The Music Tank’s repository</a> and that one features additional steps such as the integration of <a href="https://codacy.com/">Codacy</a>.</p>
<figure class="highlight"><pre><code class="language-yaml" data-lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="m">2</span>
<span class="na">jobs</span><span class="pi">:</span>
<span class="na">build</span><span class="pi">:</span>
<span class="na">docker</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">image</span><span class="pi">:</span> <span class="s">misterio92/ci-php-node</span>
<span class="na">steps</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">checkout</span>
<span class="pi">-</span> <span class="na">restore_cache</span><span class="pi">:</span>
<span class="na">keys</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">composer-cache-{{ checksum "composer.json" }}</span>
<span class="pi">-</span> <span class="s">composer-cache-</span>
<span class="pi">-</span> <span class="s">dependency-cache-{{ checksum "package.json" }}</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Installing PHP packages</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">composer install -n --prefer-dist --ignore-platform-reqs --optimize-autoloader</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Installing NPM packages</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">npm install</span>
<span class="pi">-</span> <span class="na">save_cache</span><span class="pi">:</span>
<span class="na">key</span><span class="pi">:</span> <span class="s">composer-cache-{{ checksum "composer.json" }}</span>
<span class="na">paths</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">vendor</span>
<span class="pi">-</span> <span class="na">save_cache</span><span class="pi">:</span>
<span class="na">key</span><span class="pi">:</span> <span class="s">dependency-cache-{{ checksum "package.json" }}</span>
<span class="na">paths</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">./node_modules</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Building production package</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">npm run production</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Unit tests</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">vendor/bin/phpunit</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Add server keys</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">ssh-keyscan 138.197.148.166 >> ~/.ssh/known_hosts</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Deployment</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">rsync -avzp --delete --exclude-from '.rsyncignore' . circleci@138.197.148.166:/var/www/themusictank.com</span>
<span class="pi">-</span> <span class="na">run</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s">Post deploy</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">ssh circleci@138.197.148.166 "cd /var/www/themusictank.com && php artisan route:cache"</span></code></pre></figure>Configuring your projects to use continuous integration (CI) and continuous distribution (CD) is a great way of ensuring their integrity from the moment you commit to the moment the projects make their ways to production.