<?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: Stéphane Bisinger</title>
    <description>The latest articles on Forem by Stéphane Bisinger (@kjir).</description>
    <link>https://forem.com/kjir</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%2F18401%2F3a80821e-3b16-4e60-8b83-460cd759414c.jpg</url>
      <title>Forem: Stéphane Bisinger</title>
      <link>https://forem.com/kjir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kjir"/>
    <language>en</language>
    <item>
      <title>Making a team more effective - by having fun!</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Sat, 09 Nov 2019 21:41:12 +0000</pubDate>
      <link>https://forem.com/kjir/making-a-team-more-effective-by-having-fun-mf0</link>
      <guid>https://forem.com/kjir/making-a-team-more-effective-by-having-fun-mf0</guid>
      <description>&lt;p&gt;During the last year I've been involved with the reengineering effort at &lt;a href="https://www.homegate.ch/en/"&gt;Homegate&lt;/a&gt;. These 15 months have been very intense, full of ups and downs, hard work and awesome colleagues.&lt;/p&gt;

&lt;p&gt;I still remember the first days: the team I had in front of me was having a hard time trusting each other and people seemed not very close to each other. While there were some hints of best practices, there was a need for a lead to set the direction and ignite the engine of self-improvement. That's where I decided to make an impact.&lt;/p&gt;

&lt;p&gt;A year later here I am collecting advice on how to make your teams more effective and how to introduce new ideas successfully. Transforming teams into the better version of themselves, make people grow professionally and personally is such an inspiring job!&lt;/p&gt;

&lt;p&gt;And although I have decided to move on to new challenges outside of Homegate, I want to continue working on improving teams in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Growing the full potential of a team
&lt;/h2&gt;

&lt;p&gt;I came to Homegate after the shutdown of siroop, where I learned that yes, it is possible to apply great engineering practices and build very strong platforms through that. And that it's incredibly fun!&lt;/p&gt;

&lt;p&gt;But how could I bring those experiences over to Homegate and get a very different organization to reap the same benefits that I observed before?&lt;/p&gt;

&lt;p&gt;Here are some tips that come from my direct experience with this problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen to the team
&lt;/h3&gt;

&lt;p&gt;The people in the team are the first to know what the pain points are. They might even know the solution to the problem, but not how to push it forward. Or they might need ideas on how to tackle it. Either way, this is the best place to start because you already have buy-in from the team. And once they see the results, they'll trust in your other ideas a little more, even if they look completely crazy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the mechanisms for change in the team
&lt;/h3&gt;

&lt;p&gt;The team itself needs to be in control of their change process. This means that if they're not already in place, it's up to you to try and introduce mechanisms where the team can discuss issues and agree on solutions together.&lt;/p&gt;

&lt;p&gt;At Homegate there was already a good retrospective in place, which became the best place to point out things that could be done differently to achieve better results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Work with the people
&lt;/h3&gt;

&lt;p&gt;Change is never introduced successfully through force. Any practice that is mandated from above will be resisted, no matter how good it is. If you want to bring lasting change, you need to get the people on board. You can give some inputs to push them a little bit out of their comfort zone, ultimately the team has to want to do the experiment and see.&lt;/p&gt;

&lt;p&gt;People on the team are your most important asset and you must never lose sight of that: ultimately efficiency of processes doesn't matter if the people are unhappy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Take little steps
&lt;/h3&gt;

&lt;p&gt;If you are fortunate enough that the team gives you credit it is your responsibility not to abuse it. Stepping out of the comfort zone is necessary to grow and learn, but you can't go too far out. Identify the area you want to improve, challenge some limits in a small but meaningful way, give it time to sink in, rinse and repeat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Each team and company is unique
&lt;/h3&gt;

&lt;p&gt;It doesn't matter how well something worked in a different team at a different company: you have to adapt everything to your current situation. What worked previously might not work here. To quote &lt;a href="https://youtu.be/fH4gqsIYzyE?t=1740"&gt;Kent Beck&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;I can't teach you to be more like Facebook, I can teach you to be like &lt;strong&gt;YOU at your best&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example pair programming worked great at siroop. It also worked at Homegate, although we used it in a different way. What if you find yourself in a remote company with team members distributed acroos time zones? It probably won't work as good: while it is feasible, it loses some of the advantages of pairing and a lot of the advantages of remote work. In that context, you might want to try something else to reach the same goals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tackle the big problems first
&lt;/h3&gt;

&lt;p&gt;It's a good idea to spend a little time to identify what are the biggest factors that hold the team back, and then start working on those. Much like performance work in computer programs, the biggest opportunities are behind the biggest problems, and they usually require a limited amount of effort to already improve the situation.&lt;/p&gt;

&lt;p&gt;For example when I started I noticed that work tended to stay for weeks on a branch before being merged. So I start to show how you could slice work into smaller chunks, point out opportunities to split the pull requests and generally transmit the benefits of having small, readable pull requests.&lt;/p&gt;

&lt;p&gt;After some time the changes started to become smaller and faster to be merged, which dramatically reduced the amount of big merges that caused so many problems and slowdowns. And people were happier about that too!&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep the bus factor high
&lt;/h3&gt;

&lt;p&gt;When introducing new ideas to the team you might have to lead by example and be the first to do it. This is not enough. Once you have solved a problem, you not only have to show the team the how and why, but you have to ensure they are able to do it too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be patient
&lt;/h3&gt;

&lt;p&gt;Changing people's habits takes time. I spent 6 months before we reached Continuous Delivery without any manual step. It took close to a year to get people to try not having code reviews when code was developed by a pair.&lt;/p&gt;

&lt;p&gt;Be patient, give everyone the appropriate time to get used to new concepts, and keep doing small steps whenever the time is ripe. Slow but steady always wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do high performing teams look like?
&lt;/h2&gt;

&lt;p&gt;One year later, how can we tell if the efforts paid off?&lt;/p&gt;

&lt;p&gt;There are many metrics that one could look at, but all of them are imperfect. So instead of trying to find the perfect measures, I'll point out the aspects that make me particularly proud to be part of the team and to have helped to get there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Everybody understands most of the project&lt;/strong&gt;
Even though there are varying levels of expertise among the people which tends to naturally make more experienced people as the knowledge holders, most of the team understands the pieces that make up the project, what tools or processes we have in place and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployments are non-events&lt;/strong&gt;
We deploy multiple times a day straight to production and we never have to worry about introducing big errors. Our testing strategy, our delivery pipeline and our monitoring systems are realiable and have saved us from trouble numerous times before. Therefore the team trusts its system and will proactively work to improve it in case something unexpected passes the checks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decisions are a shared responsibility by the team&lt;/strong&gt;
The team decides its own fate and takes care of all the decisions that are needed. This also means that everybody is aware of the ongoing discussion points and what might come next. Nobody needs to "shield" the team from external pressure because the team is mature enough to handle it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The infrastructure supports other teams too&lt;/strong&gt;
The infrastructure built by the team allows other teams to get started quicker and build on top of what was done. The benefits go beyond the single team, but spread into the whole organization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reported bugs are minor&lt;/strong&gt;
Most of the reported bugs are either missing features, edge cases or minor problems. The number of critical problems that require immediate intervention are stuck at _ &lt;strong&gt;zero&lt;/strong&gt; _.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No overtime required - ever!&lt;/strong&gt;
Our system is designed so that errors are unlikely and recovery is quick and painless. This means that nobody has to do overtime to solve an unexpected bug in production, because the easiest fix is to revert and have a look at it the following day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;People are better at what they do&lt;/strong&gt;
The growth in the single people is definitely noticeable. Not just on the technical side, but also in the way of collaboration with others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a team I am proud to be a member of.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Reading
&lt;/h2&gt;

&lt;p&gt;If you found this article interesting you might want to check out the following resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/theburningmonk/breaking-the-senior-developer-ceiling-bj2"&gt;Breaking the "Senior engineer" ceiling&lt;/a&gt; by Yan Cui&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nicolefv.com/book"&gt;Accelerate: Building and Scaling High Performing Technology Organizations&lt;/a&gt; by Nicole Forsgren, PhD, Jez Humble and Gene Kim&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://charity.wtf/2019/10/28/deploys-its-not-actually-about-fridays/"&gt;Deploys: It's not actually about Fridays&lt;/a&gt; by Charity Majors&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>What Is MapReduce?</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Thu, 28 Jun 2018 09:02:03 +0000</pubDate>
      <link>https://forem.com/kjir/what-is-mapreduce-25i6</link>
      <guid>https://forem.com/kjir/what-is-mapreduce-25i6</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://www.sbisinger.ch/2018/06/01/what-is-mapreduce/"&gt;my blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this era of Big Data and the rise of a new species called &lt;em&gt;Data Scientist&lt;/em&gt;, us &lt;em&gt;"mere"&lt;/em&gt; Software Developers might have heard of a thing called MapReduce, but what is it really? And why has it been a game-changing tool in the last decade? This is my attempt to explain the concept in simple terms.&lt;/p&gt;

&lt;p&gt;To illustrate the concepts I will use Python, one of the most popular languages especially when it comes to data science, and LISP (in particular Clojure) to honor the language that introduced the concepts used for MapReduce.&lt;/p&gt;

&lt;p&gt;So what is MapReduce? It is an approach to solve some problems that allow us to process huge amounts of data in a very simple way. It was described in a &lt;a href="https://ai.google/research/pubs/pub62"&gt;Google whitepaper&lt;/a&gt; in 2004, and it has been the basis for tools like Apache Hadoop, among others.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old reliable way
&lt;/h2&gt;

&lt;p&gt;But let's not lose ourselves with abstract descriptions and let us start from the very beginning - with a simple loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok that's not very idiomatic, is it? Here is a better version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;powers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm sure everyone who can write the above code understands what is going on here: we have an array of some sorts and we cycle through the elements. For each of those elements we calculate the power of 2 and place that result in a new array.&lt;/p&gt;

&lt;p&gt;It is not hard to see how this will work at a lower level, in the machine itself: the array is an area of memory, we start by pointing at the beginning this memory area, read the first value into the CPU register, multiply it by itself and store that value in another memory area that corresponds to the new array. Then proceed to the next element until the end of the array.&lt;/p&gt;

&lt;p&gt;Since we are telling exactly what the computer should do, we call this way of writing programs &lt;em&gt;imperative programming&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;em&gt;other&lt;/em&gt; old reliable way
&lt;/h2&gt;

&lt;p&gt;How would the same thing be written in LISP? It's not that complicated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;powers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whoa! What's up with all the parentheses? Okay, let's break it down in easy-to-digest pieces, shall we?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;powers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we define a function named &lt;code&gt;powers&lt;/code&gt; that takes an argument, &lt;code&gt;numbers&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates an anonymous function that takes an argument &lt;code&gt;number&lt;/code&gt;. In python you would accomplish the same with &lt;code&gt;lambda number: ...&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This looks a bit weird at first, but it just means that we multiply &lt;code&gt;number&lt;/code&gt; by itself!&lt;/p&gt;

&lt;p&gt;Now for the juicy part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meet our new friend &lt;code&gt;map&lt;/code&gt;! What this function does is simple: return a list of values that are the result of the function passed in as the first argument applied to every item of the list passed in as the second argument.&lt;/p&gt;

&lt;p&gt;Or to put it differently, &lt;code&gt;map&lt;/code&gt; will loop through every value in &lt;code&gt;numbers&lt;/code&gt;, apply our function to each value, and return the result of this function in a new list. It is the equivalent of our for loop!&lt;/p&gt;

&lt;p&gt;But let's reflect for a second on what happens at a lower level: from the code we see we actually can't know how this will play out! Will we walk through the memory in the same order as with the for loop? Or in reverse order? Or with some random order? We can't be sure because the detail of how to produce the result is not in our hands, but it is taken care by the implementation of our programming language.&lt;/p&gt;

&lt;p&gt;This is what is called &lt;em&gt;functional programming&lt;/em&gt;, which is a form of &lt;em&gt;declarative programming:&lt;/em&gt; we state what we want, not how to produce our result. But why is this important? Is it just a matter of style and personal taste?&lt;/p&gt;

&lt;h2&gt;
  
  
  Thinking Big Data
&lt;/h2&gt;

&lt;p&gt;Our example is small enough that the way we loop through the data doesn't matter. But what if instead we had a very big list of numbers, greater than what can be held in memory? What if instead of multiplying we had to perform a more CPU-intensive function? How would this play out?&lt;/p&gt;

&lt;p&gt;This is a scenario where you might want to introduce some form of parallelism, to use all of your CPU cores. How would that look with our Python example?&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# To use Threads, we would use ThreadPoolExecutor
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;NUM_WORKERS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;futures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expensive_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;concurrent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;future&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complexity went definitely up! And this is taking advantage of the &lt;code&gt;concurrent.futures&lt;/code&gt; module, which simplifies already a lot of details.&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;What about LISP?&lt;/p&gt;

&lt;p&gt;Here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expensive-function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only relevant change is that we use &lt;code&gt;pmap&lt;/code&gt; instead of &lt;code&gt;map&lt;/code&gt;, and the only reason we have to change function at all is because it might not always be desirable to run the function in separate threads. That's not just a matter of programming styles or syntactic sugar, this is actually a very big deal!&lt;/p&gt;

&lt;p&gt;Now let's extend the reasoning even further: what if we have so much data to process, maybe from a file of a few gigabytes or even terabytes, and we can't possibly process all of that on one computer. We have to distribute the load over hundreds or thousands of servers! How can we do that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributing work
&lt;/h2&gt;

&lt;p&gt;How could we split our work across various servers, instead of having it in separate threads or processes? This is where it starts to get hairy. We have to manage somehow our cluster of servers, ensure they are reachable, distribute the work, handle failures and retries, and ideally also scale them automatically. Seems complicated? Well it is, and since we are talking about a distributed system there are many ways things can fail and countless pitfalls to avoid. Distributed systems are hard to implement correctly.&lt;/p&gt;

&lt;p&gt;So how would our code look like in Python? Honestly, I don't even want to start with it. It would be an immense effort to accomplish this and it would certainly not fit in this blog post. A possible idea could be to use Celery to enqueue the slices of computations and use that to distribute the load across different hosts.&lt;/p&gt;

&lt;p&gt;How would it look in LISP? Theoretically, it doesn't need to change: we could have a &lt;code&gt;dmap&lt;/code&gt; function that distributes work across multiple nodes. In practice it is a bit more complicated than that just because we would need to setup our cluster and control its behaviour.&lt;/p&gt;

&lt;p&gt;I don't want to leave you without an example, though, so here is one written in Python, using a library called&lt;br&gt;
&lt;a href="http://scoop.readthedocs.io"&gt;Scoop&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;scoop&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;futures&lt;/span&gt;

&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;futures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expensive_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you tell from the code that this might actually run on multiple machines?&lt;/p&gt;

&lt;h2&gt;
  
  
  But what about reduce?
&lt;/h2&gt;

&lt;p&gt;We talked at length about the &lt;code&gt;map&lt;/code&gt; operation, but we haven't mentioned the &lt;code&gt;reduce&lt;/code&gt; yet. What is it about?&lt;/p&gt;

&lt;p&gt;I'm sure you encountered this operation quite a few times before, just look at this imperative approach to implement the operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_nums&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've done this or a variation of this a hundred times, I'm sure. It is often useful to turn an array into an hash map of some sort, for example this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;group_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;customers_map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;customers_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;customers_map&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How would this look in the functional world? Here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_nums&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again the details are hidden and we only provide a combining operation (the &lt;code&gt;+&lt;/code&gt; in our case), an initial value (&lt;code&gt;0&lt;/code&gt; which could be omitted in this particular case) and the collection.&lt;/p&gt;

&lt;p&gt;What will happen is that it will take an element from the collection combine it with our accumulator (that is the initial &lt;code&gt;0&lt;/code&gt;), use this combination as the new accumulator and proceed with the next element in our collection.&lt;/p&gt;

&lt;p&gt;If we combine it with the &lt;code&gt;map&lt;/code&gt; operation we can do some pretty powerful stuff:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;defn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum_squares&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The imperative equivalent is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_squares&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;final_sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;final_sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;final_sum&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MapReduce at last
&lt;/h2&gt;

&lt;p&gt;Now that we clarified the building blocks and the concepts behind them, it is easy to understand what MapReduce is all about. Let's take the example straight from Google's Whitepaper, which will count the occurrences of the words in a text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;    &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// key: document name&lt;/span&gt;
      &lt;span class="c1"&gt;// value: document contents&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;EmitIntermediate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// key: a word&lt;/span&gt;
      &lt;span class="c1"&gt;// values: a list of counts&lt;/span&gt;
      &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ParseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AsString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first define a map operation, that for each document it receives, it will split it into words and for each word emit a key/value pair, where the key is the word itself an the value is &lt;code&gt;1&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;The reduce function will then receive the key and the list of values that correspond to that key. In our case for each word we would receive a list of ones, one for each repetition of the word.&lt;/p&gt;

&lt;p&gt;We then take all of those ones and we sum them together. This is then the value that we emit.&lt;/p&gt;

&lt;p&gt;All of this actually happens in a distributed manner, but the code doesn't really need to know. How cool is that?&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this the end?
&lt;/h2&gt;

&lt;p&gt;Is that all there is to it? Mostly, yes. Of course there is much more to know, but the basic idea is &lt;strong&gt;that&lt;/strong&gt; simple. From this idea other cool things were built, to the point that &lt;a href="https://www.youtube.com/watch?v=AZht1rkHIxk"&gt;No one at Google uses MapReduce anymore&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;I hope that this will allow you to understand better what the concepts are behind MapReduce and to have a general feeling about what it allows you to do. Between this and actually using it there are many more steps to make, but maybe now it looks less intimidating.&lt;/p&gt;

&lt;p&gt;Was this helpful? Let me know in the comments!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Due to the Global Interpreter Lock, we are actually spawning multiple processes here. Python threads are useless for CPU-intensive operations. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;With the executors you can use executor.map, which is a approach to the problem. This highlights how powerful this really is. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>functional</category>
      <category>learning</category>
      <category>bigdata</category>
    </item>
    <item>
      <title>Time for Growth</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Mon, 28 May 2018 15:02:19 +0000</pubDate>
      <link>https://forem.com/kjir/time-for-growth-21m5</link>
      <guid>https://forem.com/kjir/time-for-growth-21m5</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/kjir/my-tech-wishlist-1nkg"&gt;last post&lt;/a&gt; I listed the technologies I'm curious about, but I also listed some of the technologies I'm not so enthusiastic about. That triggered some reactions and &lt;a href="https://dev.to/manigandham/comment/31k8"&gt;someone pointed out to me&lt;/a&gt; that my knowledge about C# and Java is outdated.&lt;/p&gt;

&lt;p&gt;This has been the beginning of a soul-searching process on my part. &lt;/p&gt;

&lt;h2&gt;
  
  
  A problem of arrogance?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Rather than seeking to find out more through questions and learning (actions viewed by them as showing vulnerability), arrogant people tend to generalize from their limited, narrow life experiences and try to impose their small worldview on others.&lt;br&gt;
— &lt;a href="https://www.wikihow.com/Detect-Arrogant-People"&gt;How to Detect Arrogant People&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I stumbled upon the previous quote and, while I find it a little harsh, it doesn't paint a pretty picture. Am I confining myself to the small enclosure of my own comfort zone, forgetting to question it from time to time?&lt;/p&gt;

&lt;p&gt;Since I've always made it a point to keep my open mindedness as wide as possible, I decided to do something about it in order to improve. The time has come to let go of some stiff ideas that get in the way, challenge my beliefs and grow up as a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conquering the mountain of my ego
&lt;/h2&gt;

&lt;p&gt;A journey of a thousand miles begins with a single step, says ancient Chinese lore, so I started to take some baby steps in that direction. I found some very inspiring insights in the videos by &lt;a href="https://dev.to/jaymeedwards"&gt;Jayme Edwards&lt;/a&gt;, who shares what he has learned over the years as a software developer in order to lead more healthy professional lives.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8i8B_3OTSjM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;His approach really inspired me and made me realize that it's more important to me to be helpful on a project or organization rather than being an ass about technological choices: while I have my preferences and ideas, I can't let these things get in the way of making a positive impact.&lt;/p&gt;

&lt;p&gt;I also decided that an update in popular technologies outside my usual picks is overdue, so I went ahead and invested some time there.&lt;/p&gt;

&lt;h2&gt;
  
  
  New discoveries
&lt;/h2&gt;

&lt;p&gt;The first thing I wanted to find out was how it would look like if I wanted to&lt;br&gt;
start a project in .NET, for example a simple API. I didn't want to install .NET Core on my machine, so I opted for docker images. I created &lt;a href="https://github.com/Kjir/privy-canister/tree/master/todo-fsharp"&gt;a small F# project&lt;/a&gt; and I was surprised! There are relatively few obstacles to get started and while it still requires some configuration files, the available documentation is excellent and all the basics are already covered. Kudos!&lt;/p&gt;

&lt;p&gt;Next I decided to find out what has been happening in the Java world since 2012. And to my great surprise the introduction of lambda expressions is a bigger deal that I thought! Coupled with the new Stream API, the power of Java has been greatly extended.&lt;/p&gt;

&lt;p&gt;For example, to loop through an array we can turn this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;asList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While there are still a lot of limitations due to the way object orientation was implemented in the language, this is already a great improvement!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;I am glad to make this effort to widen my horizons. I might never be an actual fan of some technologies, but I decided to stop treating this as a deal-breaker. Instead I'll give more importance to the people involved in a project and the potential positive impact that I can have.&lt;/p&gt;

&lt;p&gt;Truth is, horrible code can come from any language, but it is also true that with (almost) any language you can build awesome stuff. And regardless, at the end of the day I am going to work with people, not programming languages, and if the people are cool and I can be of help, what more could I wish for?&lt;/p&gt;

</description>
      <category>career</category>
      <category>learning</category>
      <category>mentalhealth</category>
    </item>
    <item>
      <title>My Tech Wishlist</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Mon, 16 Apr 2018 19:55:56 +0000</pubDate>
      <link>https://forem.com/kjir/my-tech-wishlist-1nkg</link>
      <guid>https://forem.com/kjir/my-tech-wishlist-1nkg</guid>
      <description>&lt;p&gt;Due to &lt;a href="https://www.coop.ch/de/ueber-uns/medien/medienmitteilungen/2018/coop-uebernimmt-swisscom-anteile-an-siroop.html"&gt;some big changes&lt;/a&gt; involving the company I'm currently working at, I will soon move on to a new challenge.&lt;/p&gt;

&lt;p&gt;But what are the challenges I'd like to work on in the next months?&lt;br&gt;
Here is &lt;em&gt;my list&lt;/em&gt; with things that excite me and things that don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Job Utopia?
&lt;/h2&gt;

&lt;p&gt;Finding a job that would match all the following criteria is impossible. As&lt;br&gt;
with any wishlist, this is just a listing of what currently interests me: some&lt;br&gt;
things are negotiable, some are not. The objective is to collect my thoughts in&lt;br&gt;
one place, so that I have a reference to compare potential job offers with. It&lt;br&gt;
can also help potential employers understand more what kind of person I am.&lt;/p&gt;

&lt;h2&gt;
  
  
  Company values
&lt;/h2&gt;

&lt;p&gt;One of the most important points for me when looking for a new job is to verify the company values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Must haves
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A clear purpose&lt;/strong&gt;: I recently read &lt;a href="https://www.goodreads.com/book/show/7108725-start-with-why"&gt;Start with
Why&lt;/a&gt; from Simon
Sinek and it struck me for its simplicity. A company should be able to answer
to a very simple question: &lt;em&gt;Why should it exist?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A positive impact&lt;/strong&gt;: &lt;em&gt;Choose a job you love, and you will never have to
work a day in your life&lt;/em&gt;. If what you do improves people's lives, I'd love to
hear from you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good working conditions&lt;/strong&gt;: This means european levels of social benefits
and working conditions that help taking care of a family. A successful
company should know better ways to track productivity than using a clock.
Quality over quantity!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Influence&lt;/strong&gt;: I am enthusiastic and opinionated; I love challenges and I
want my work to be impactful. I want the company I work for to be successful,
but to do that I must be able to influence it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;After 15 years spent in web development, I long for bigger challenges. Making an application perform and scaling it to handle big volumes of traffic is not an easy feat!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes&lt;/strong&gt;: Containerization has changed the way we deploy our software,
but other things haven't changed: vendor lock-ins versus free software.
Platforms like AWS are amazing, but I always ask myself if it's wise to be
locked to a specific platform. Kubernetes allows you to choose from a wide
array of hosting options, and you still have the door open to migrate
somewhere else if you ever need to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data streaming&lt;/strong&gt;: I've worked with DynamoDB and Lambdas to process data in
streams, but I found the artificial limitations really bothersome. I want to
go a step forward and explore other options like &lt;a href="https://kafka.apache.org/"&gt;Apache
Kafka&lt;/a&gt;, &lt;a href="https://flink.apache.org/"&gt;Apache Flink&lt;/a&gt;
or others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Programming languages
&lt;/h2&gt;

&lt;p&gt;Over my career I've worked with a plethora of different programming languages and while all can accomplish great things I obviously have my preferences. There are interesting newcomers on the scene and I'd love to try out some of them!&lt;/p&gt;

&lt;h3&gt;
  
  
  Would love to use
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Elixir/Erlang, Elm, Clojure, Haskell, Scala&lt;/strong&gt;: Functional programming is
very hot right now and I find very interesting how some of the concepts
helped to solve modern problems (I'm looking at you, state management!). I'd
love to work professionally with one of those, also to explore their
shortcomings and &lt;em&gt;become a better programmer&lt;/em&gt; in the process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust, Go&lt;/strong&gt;: Those are relatively new kids on the block! Using modern
programming languages to write (relatively) low-level programs must be fun,
right?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python, Ruby&lt;/strong&gt;: The old reliables. Yes, I've worked with them already, and
yes, they still excite me! I know their limitations, but I also know how to
overcome them when necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Not so eager
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Java&lt;/strong&gt;: I find Java extremely boring. I think Java might be the main
reason I'm not a fan of statically typed languages! I mean to this day you
need XML (yuck!) and an IDE to generate code for you if you want to keep
your sanity. Its love for abstractions really clashes with my minimalist
approach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;C#&lt;/strong&gt;: Although I've never been a fan of Microsoft, I must admit that in
the last years they changed their approach completely. Nonetheless, C# is
still very close to Java and I'm not sold on developing on Windows. The
vendor lock-in concern is still present with the .NET platform. Maybe I
could be swayed with F#, if the project is really interesting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP&lt;/strong&gt;: I've started my career with ASP and PHP, I've worked numerous
times with PHP and... I can't take it anymore! It just doesn't excite me at
all, it is bothersome for me to write (why &lt;code&gt;-&amp;gt;&lt;/code&gt; instead of &lt;code&gt;.&lt;/code&gt;??) and I
think the type hinting is actually making the language worse! If I see PHP
on a job ad it is very likely to be a deal breaker for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Quite a list, isn't it? If you are a fellow developer, what is your list of dream requisites for a new job?  Let me know in the comments!&lt;/p&gt;

&lt;p&gt;Are you on the lookout for developers? Do you think I would be a good match for your team, either remotely or in Zurich? Then &lt;a href="//mailto:stephane.bisinger@protonmail.com"&gt;get in touch&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>career</category>
      <category>job</category>
    </item>
    <item>
      <title>Hi, I'm Stéphane Bisinger</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Sun, 11 Jun 2017 10:15:58 +0000</pubDate>
      <link>https://forem.com/kjir/hi-im-stphane-bisinger</link>
      <guid>https://forem.com/kjir/hi-im-stphane-bisinger</guid>
      <description>&lt;p&gt;I have been coding for around 17 years.&lt;/p&gt;

&lt;p&gt;You can find me on GitHub as &lt;a href="https://github.com/Kjir" rel="noopener noreferrer"&gt;Kjir&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in the beautiful city of Zürich, Switzerland.&lt;/p&gt;

&lt;p&gt;I work for &lt;a href="https://www.renuo.ch/" rel="noopener noreferrer"&gt;Renuo&lt;/a&gt;, a small Ruby-based Web Agency.&lt;/p&gt;

&lt;p&gt;I mostly program in Ruby and Javascript.&lt;/p&gt;

&lt;p&gt;I am currently learning more about Elixir and Functional Programming, also applied to React and Javascript.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
    <item>
      <title>A modular Gruntfile</title>
      <dc:creator>Stéphane Bisinger</dc:creator>
      <pubDate>Sun, 14 Feb 2016 21:02:00 +0000</pubDate>
      <link>https://forem.com/kjir/a-modular-gruntfile-4l94</link>
      <guid>https://forem.com/kjir/a-modular-gruntfile-4l94</guid>
      <description>&lt;p&gt;&lt;a href="http://www.gruntjs.com/"&gt;Grunt&lt;/a&gt; is a very powerful task runner and if you are developing in Javascript chances are you are probably using it. It’s configuration file defines all the tasks available and what they should do, but have you ever felt that even for mid-sized projects it easily becomes too big and hard to manage?&lt;/p&gt;

&lt;p&gt;Well I felt that way, so that’s when I decided to split it into many smaller configuration files with the help of &lt;a href="http://firstandthird.github.io/load-grunt-config/"&gt;load-grunt-config&lt;/a&gt;. By following the excellent advice given by &lt;a href="https://paulbakaus.com/"&gt;Paul Bakaus&lt;/a&gt; on &lt;a href="http://www.html5rocks.com/en/tutorials/tooling/supercharging-your-gruntfile/"&gt;his article on html5rocks&lt;/a&gt;, I came up with a cleaner and much more manageable setup.&lt;/p&gt;

&lt;p&gt;Here I’ll try to build upon his article to add some more details about useful tricks I used in my setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  The brevity of YAML
&lt;/h2&gt;

&lt;p&gt;Being at heart a Python developer, I love terse syntax. Why bother with unnecessary brackets, commas or quotes which clutter your files making them harder to read for the human eye? Hence a move from a Javascript syntax to a YAML syntax for a configuration file is a big relief for me!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;load-grunt-config&lt;/code&gt; supports many different kinds of syntax files, which can be mixed, allowing me to greatly reduce the noise in my configuration. If I initially had a &lt;code&gt;Gruntfile&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;package.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;ngconstant&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/config/config.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyApp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pkg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;version&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:3000/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;staging&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://staging.example.com/api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I would now have this as a &lt;code&gt;Gruntfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load-grunt-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I would create a YAML configuration file in &lt;code&gt;grunt/ngconstant.yaml&lt;/code&gt;:&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;options&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config'&lt;/span&gt;
  &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/config/config.js'&lt;/span&gt;
  &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
      &lt;span class="na"&gt;appID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MyApp'&lt;/span&gt;
      &lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;package.version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;'&lt;/span&gt;
  &lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000/api'&lt;/span&gt;
  &lt;span class="na"&gt;staging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://staging.example.com/api'&lt;/span&gt;
  &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isn’t this cleaner? And it’s shorter, too!&lt;/p&gt;

&lt;p&gt;Also notice how I did not have to manually parse my &lt;code&gt;package.json&lt;/code&gt; to access its values? This is another nice feature of &lt;code&gt;load-grunt-config&lt;/code&gt;’s which comes in handy. All you need to do is to read your values using a grunt template like&lt;code&gt;'&amp;lt;%=package.version%&amp;gt;'&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing values between tasks
&lt;/h2&gt;

&lt;p&gt;In my project I used to have some variables holding some values shared by many different tasks. Lets take for instance the files list, which can be used by&lt;code&gt;concat&lt;/code&gt;, but also by &lt;code&gt;uglify&lt;/code&gt; or &lt;code&gt;copy&lt;/code&gt; or whatever. So I had something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;

    &lt;span class="c1"&gt;// Application files&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/**/*.module.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/module/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/component/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/service/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// Do not include tests in application build&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!app/**/*.test.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;!app/**/*_test.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;jshint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;jshintrc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;uglify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist/app/js/&amp;lt;%= package.name %&amp;gt;.min.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sourceMap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How can I do to share these values across tasks now that they each live in their own file? Well first I created a &lt;code&gt;grunt/project.yaml&lt;/code&gt; file holding these values:&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;files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Application files&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/**/*.module.js'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/module/**/*.js'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/component/**/*.js'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/service/**/*.js'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/app.js'&lt;/span&gt;
    &lt;span class="c1"&gt;# Do not include tests in application build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!app/**/*.test.js'&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;!app/**/*_test.js'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here’s the magic in the &lt;code&gt;grunt/jshint.yaml&lt;/code&gt; file:&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;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jshintrc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;project.files&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the same goes for &lt;code&gt;grunt/uglify.yaml&lt;/code&gt;:&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;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;project.files&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;'&lt;/span&gt;
  &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dist/app/js/&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;package.name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;.min.js'&lt;/span&gt;
  &lt;span class="na"&gt;sourceMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That was easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Separating configuration files by environment
&lt;/h2&gt;

&lt;p&gt;As you could see, in my project I use &lt;a href="https://github.com/werk85/grunt-ng-constant"&gt;grunt-ng-constant&lt;/a&gt; to create an appropriate configuration file according to the environment. I also use &lt;a href="https://github.com/jsoverson/grunt-env"&gt;grunt-env&lt;/a&gt; in combination with &lt;a href="https://github.com/jsoverson/grunt-preprocess"&gt;grunt-preprocess&lt;/a&gt; to configure my &lt;code&gt;index.html&lt;/code&gt; file differently according to the environment. I wanted to have a single file with all the configuration for a single environment so that it would be easier to verify and change them, and once again &lt;code&gt;load-grunt-config&lt;/code&gt; came to the rescue!&lt;/p&gt;

&lt;p&gt;I used &lt;a href="http://firstandthird.github.io/load-grunt-config/#toc7"&gt;config grouping&lt;/a&gt; to do that:&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;# File: development-tasks.yaml&lt;/span&gt;
&lt;span class="na"&gt;ngconstant&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;package.version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;-dev'&lt;/span&gt;
    &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://devel.example.com/api'&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;DEVELOPMENT'&lt;/span&gt;
  &lt;span class="na"&gt;THEME_CSS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;css/mytheme.devel.css'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using this configuration I can now have a separate file for each environment. The &lt;code&gt;grunt/ngconstant.yaml&lt;/code&gt; and &lt;code&gt;grunt/env.yaml&lt;/code&gt; files become like this:&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;# File: grunt/ngconstant.yaml&lt;/span&gt;
&lt;span class="na"&gt;options&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;config'&lt;/span&gt;
  &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/config/config.js'&lt;/span&gt;
  &lt;span class="na"&gt;constants&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# These are all default values&lt;/span&gt;
    &lt;span class="na"&gt;ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;appName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MyApp'&lt;/span&gt;
      &lt;span class="na"&gt;appVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;%=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;package.version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;%&amp;gt;'&lt;/span&gt;
    &lt;span class="na"&gt;apiLocation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://api.example.com/api/v1'&lt;/span&gt;

&lt;span class="c1"&gt;# File: grunt/env.yaml&lt;/span&gt;
&lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;THEME_CSS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;css/mytheme.css'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, there are only the default options there and no environment specific configuration.&lt;/p&gt;

&lt;p&gt;I also wanted to separate the environment-specific configuration files from the standard task configurations, so that the context would be clear. So I put them all in a &lt;code&gt;config&lt;/code&gt; directory, which I created, and modified our &lt;code&gt;Gruntfile.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load-grunt-config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;grunt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;configPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;grunt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;// Task settings here&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Environment specific settings here&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="cm"&gt;/*
     * If you want to change your setting locally without changing what is on
     * the repo, you can define your configuration overrides in config/override
     */&lt;/span&gt;
    &lt;span class="na"&gt;overridePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;override&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;load-grunt-config&lt;/code&gt; also supports overrides, which is another nice feature: as I set it up, you can create a configuration file in &lt;code&gt;config/override&lt;/code&gt; which will override any previously set configuration option. This is very useful to accomodate the needs of every developer which might be a little different, without having them modify the files which are under versioning. Pretty neat!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;load-grunt-config&lt;/code&gt; is a very nice grunt plugin which really improves the quality of your Gruntfile by splitting it into many smaller files. Not only that: it adds a lot of useful features that will make you wonder why bother writing plain &lt;code&gt;Gruntfile&lt;/code&gt;s anymore!&lt;/p&gt;

&lt;p&gt;Do you use &lt;code&gt;load-grunt-config&lt;/code&gt; in your project? Is there some other great feature I missed? Please leave a comment below!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
