<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://codecoolture.com</id>
    <title>Codecoolture</title>
    <updated>2026-02-05T18:47:41.407Z</updated>
    <generator>https://github.com/codecoolture/codecoolture.com</generator>
    <author>
        <name>Sergio Álvarez</name>
        <email>hola@codecoolture.com</email>
        <uri>https://codecoolture.com/about</uri>
    </author>
    <link rel="alternate" href="https://codecoolture.com"/>
    <subtitle>Articles and notes about software development. Written by Sergio Álvarez. Better code, one piece at a time.</subtitle>
    <logo>https://codecoolture.com/static/img/rss/sergio.jpg</logo>
    <rights>All rights reserved. Sergio Álvarez. 2026</rights>
    <entry>
        <title type="html"><![CDATA[My library is open]]></title>
        <id>https://codecoolture.com/notes/library</id>
        <link href="https://codecoolture.com/notes/library"/>
        <updated>2026-01-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Making my personal library public. A curated selection of books that have influenced my thinking and approach to software development.]]></summary>
        <content type="html"><![CDATA[<h1>My library is open</h1>
<p>After almost 15 years in this profession, I have accumulated quite a few books
that have influenced my thinking and approach to software development, as well
as how I interact with others. I believe they&#39;re worth sharing.</p>
<p>There is now a new page on this site showcasing all the books I consider
valuable enough to recommend (note: this is not an exhaustive list but rather a
curated selection). To make it easier to browse, I&#39;ve categorized them based on
how they&#39;ve shaped my thinking or how I&#39;ve incorporated their ideas into my
daily work.</p>
<p>Without further ado, <a href="/library">the library</a>!</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Many small pull requests]]></title>
        <id>https://codecoolture.com/blog/stacked-pull-requests</id>
        <link href="https://codecoolture.com/blog/stacked-pull-requests"/>
        <updated>2024-07-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Optimize your code review process by stacking pull requests, ensuring each introduces only one new behavior for easier, faster reviews.]]></summary>
        <content type="html"><![CDATA[<h1>Many small pull requests</h1>
<p>Okay, so you are working on a new feature. Because your team operates using a
pull request-based workflow, someone needs to review your code before it lands
in the main branch and is released to all users. In the last retrospective,
there was a lot of frustration among peers because code reviews usually take
hours or even days to complete, and still, there is a lot of rubber-stamping or
minor comments about code style (things that could be easily automated with
better linters).</p>
<p>This time, you will try to approach it a bit differently and optimize for
reviewing rather than your own immediate productivity (which gets hurt in the
long term anyway due to delays in code review). Based on your experience as a
reviewer, code reviews start to get complicated not when they involve many file
changes but when they change multiple behaviors at the same time. For example, a
pull request with 300 file changes where you&#39;re simply renaming a constant is
much easier to review than a pull request with 4 file changes that modify four
different system behaviors.</p>
<p>This time, you plan to slice your work in a way that you can create more than
one single pull request, ensuring each pull request only introduces one new
behavior into the system (a variable rename, a change to existing logic). The
only problem with this approach is that no one on the team operates this way,
and you are unsure whether it is possible to merge incomplete feature code into
the main branch or if there is a way to hold off on all the changes but still
allow for incremental reviews.</p>
<p>A few months ago, someone from the billing team shared a recent experiment using
feature flags to turn on and off certain logic in production based on a
configuration that’s easily accessed by a UI. Leveraging feature flags sounds
like a sensible approach. That way, you could wrap all the new code under a
feature flag that’s deactivated by default and only enabled once all pull
requests have been merged into the main branch and the feature is code complete.
But it seems the feature flag infrastructure is a bit experimental in the
company, and you’re unsure whether it will be safe for your team to start
relying on them.</p>
<p>But wait, there might be ways to achieve a similar code reviewing experience
(note from the author: yeah, deploying code behind feature flags offers many
more benefits than just facilitating code review, but that’s part of another
series) by stacking pull requests. For example, you can create a first branch
for your initial set of changes and then branch off again with the new set of
changes. This second pull request will be based on the first branch instead of
the main branch, so the diff is clear and only shows the new set of incremental
changes.</p>
<p>Although stacking pull requests may become a bit tricky with large feature
developments, it offers a good compromise for small to medium developments. You
just need to make sure each new set of changes branches off from the previous
branch. Then, each pull request will use the previous branch as the base branch
for comparison. You don&#39;t need to merge each pull request independently; they
are there just to facilitate the code review process. Once each step has been
approved by your team, you can create a final pull request containing all the
changes and use that to release the code. It&#39;s true the process accounts for
some minimal duplication, but the benefits of having small, reviewable units
persuade you to give it a try.</p>
<p><img src="/static/articles/stacked-pull-requests/how-it-works.jpg" alt="Diagram illustrating the stacked pull requests workflow with branches and incremental changes." title="Illustration of the stacked pull requests workflow, showing how incremental changes build upon each other for streamlined code reviews."></p>
<p>The only problem: you have never worked this way before, and typically, your
feature development is a bit chaotic. Although you know the end goal, you’re
usually figuring out the way to get there as you experiment with the codebase.
This time, however, you may need a clearer plan to slice your work correctly for
reviewing, following the principles you stated before (each pull request will
only contain one change in behavior).</p>
<p>All your teammates have small differences in the way they approach feature
development. Thinking about it for a second, you realize Sara uses something she
calls an “Implementation Plan” and regularly posts it as a comment on the issue
even before writing a single line of code. Reflecting a bit more, each step in
Sara’s implementation plan typically matches the principles you’ve stated
before: each pull request introduces only one new behavior into the system.</p>
<p>Deciding to follow Sara’s approach, you take a few hours to design a possible
solution for the problem. There might be a few surprises along the way, but the
implementation plan looks solid and has already given you some hints about how
you may slice the problem. You have already identified a little refactoring you
need to accomplish in the first instance that is better encapsulated in its own
pull request so Jose, one of the experts on that part of the system, can take a
look. Actually, now that you look at the plan, you realize it might be a good
moment to ask Sofia, the tech lead for your team, to chime in so she can give
you a thumbs-up now that you haven’t invested too much time in development.
Working in smaller batches has already proven to be helpful even before creating
the first pull request.</p>
<p>--</p>
<p>So, the little story above is just an example of how we may approach software
development in a way that favors creating many small pull requests instead of a
single one. Obviously, your mileage may vary, as may the experience around your
team, but regularly incorporating this notion of 1 pull request = 1 behavior
should facilitate both your development (because you’ll be working with less
complexity at every step) and your code review process.</p>
<p>Implementation plans are just a technique that may help you divide your work in
a way that makes sense and follows the principle we’ve stated before. They may
also contribute to other benefits such as discovering potential blockers,
incorporating feedback from your colleagues early in the process, or offering
you some guidance as you move forward with the development.</p>
<p>We have already covered how stacking pull requests may work at a high level.
Some tools support this kind of process by default (e.g., Phabricator via
stacked diffs), but a similar workflow can be easily replicated in tools such as
GitHub or GitLab (although the developer experience could be much better).</p>
<p>But as with almost everything in software, there isn’t a silver bullet. One
drawback of slicing your work this way is that reviewers may find it more
complex to see the whole picture of your changes. While this can be minimized by
offering links to previous pull requests, having all your changes in a single
pull request can make it easier for them to understand the context and scope. On
the other hand, a large pull request with dozens of changes can also be
overwhelming and, as we have discussed before, delay the overall reviewing
process because reviewers need to deal with more complexity.</p>
<p>If you&#39;re looking for cost-effective ways to improve the code review process on
your team, give stacked pull requests a try or, at the very least, aim to
conform to the rule of one behavior change = one pull request.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Effective Code Reviews]]></title>
        <id>https://codecoolture.com/blog/effective-code-reviews</id>
        <link href="https://codecoolture.com/blog/effective-code-reviews"/>
        <updated>2024-07-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This series explores how to make pull request-based code reviews more efficient and productive for both developers and reviewers.]]></summary>
        <content type="html"><![CDATA[<h1>Effective Code Reviews</h1>
<p>Many companies use pull requests as a critical part of their software
development process to achieve goals such as automated testing (via continuous
integration services) and conducting code reviews.</p>
<p>In many cases, pull requests also serve as gatekeepers to production: someone
from the organization (likely from the same team) needs to approve the changes
for development to move forward. This process is often a source of frustration
in software teams, where it is common to hear complaints about how long it takes
for a pull request to be reviewed or the lack of constructive feedback received
during code reviews.</p>
<p>On the other hand, reviewers often express frustration because pull requests are
usually very large, making them difficult to review and thus more
time-consuming. Still, many developers write code with a focus on their own
productivity instead of optimizing for the later, required step of code
reviewing.</p>
<p>In this series, I&#39;d like to explore ways to make code reviews more productive
for everyone: developers who want to receive constructive feedback while
releasing software on time, and code reviewers who want to set a high-quality
standard and use code reviews as a tool to leverage collective learning and
knowledge sharing.</p>
<h2>But first...</h2>
<p>Pull requests, or pull request-based workflows, are just one option for
collaborative work. I&#39;m aware that other teams use more lightweight approaches,
such as <a href="https://trunkbaseddevelopment.com/">trunk-based development</a>, where all
commits are made directly to the main branch. This method relies on a highly
sophisticated continuous integration infrastructure to validate each commit
before it gets released.</p>
<p>There are also companies that focus heavily on pair or ensemble programming
sessions, thereby reducing the need for asynchronous work. Still, highly
distributed companies or teams that prefer a more asynchronous approach may
choose pull requests to review code.</p>
<p>Ultimately, this series is not advocating for a pull request workflow but rather
highlighting ways to make it more productive.</p>
<h2>Read the full series</h2>
<ol>
<li><a href="/blog/stacked-pull-requests">Many small pull requests</a></li>
<li>...more coming soon!</li>
</ol>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Opinions]]></title>
        <id>https://codecoolture.com/notes/opinions</id>
        <link href="https://codecoolture.com/notes/opinions"/>
        <updated>2023-08-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A collection of thoughts and ideas about running software projects.]]></summary>
        <content type="html"><![CDATA[<h1>Opinions</h1>
<p>Don’t make everybody busy from day one. Use the first stages of a software
project to facilitate mob programming sessions and create a shared
understanding.</p>
<p>Embrace some early duplication. Use the first few weeks to explore the problem
space and try different approaches. Removing duplication is often easier than
dealing with flawed architectures.</p>
<p>Optimize for short feedback loops. Trunk-based development, test-driven
development, or continuous deployment are techniques that guide the team toward
this objective.</p>
<p>For your initial test suite, optimize for confidence rather than speed (you can
always fix performance later). That usually means creating more
acceptance/integration tests than unitary ones. Also, tests of higher
granularity levels help to develop test-friendly software systems.</p>
<p>When writing documentation, use how-to guides (how to execute a background job,
how to log analytics events) and architecture decision records (so everybody can
understand the WHY of certain design decisions).</p>
<p>Tackle the tasks with the most uncertainty first.</p>
<p>Simple !== Easy, but beware, they are often confused (perhaps because simple
solutions are harder to design and implement).</p>
<p>Good software design <strong>always</strong> pays off.</p>
<p>Slice the work wisely. Rather than slicing by technical layers (for example,
creating one task for front-end work and another for back-end work), use slices
that make business sense and provide value (i.e., the minimum viable feature).
Vertical slices enable shorter feedback loops and reduce integration problems.</p>
<p>If using a pull-requests-based workflow, avoid the notion of one feature = one
pull request. Use <em>stacked</em> pull requests to generate smaller reviewable units.</p>
<p>Keep your options open, especially at the beginning. Use the
<a href="https://blog.codinghorror.com/the-last-responsible-moment/">Last Responsible Moment</a>
technique to drive your decision-making process.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[React: Using children instead of dedicated render slots]]></title>
        <id>https://codecoolture.com/blog/react-compound-components</id>
        <link href="https://codecoolture.com/blog/react-compound-components"/>
        <updated>2022-12-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Let's improve our components API by using compound components instead of render props.]]></summary>
        <content type="html"><![CDATA[<h1>React: Using children instead of dedicated render slots</h1>
<p>Using component props to pass data (or <code>JSX</code> elements directly) that will later
populate internal UI pieces has been a prevalent pattern in the React community,
trying (probably) to emulate <a href="https://vuejs.org/guide/components/slots.html#named-slots">the better-designed slot approach adopted by
Vue</a>.</p>
<p>For example, imagine we are coding a new <code>Nav</code> component for our site. It will
render a collection of nav items, the page title, and a call to action link.
Each page might customize any of these elements.</p>
<p>Not surprisingly, I think either of these two would be the most popular examples
we might find out there (or a combination of both):</p>
<pre><code class="language-jsx">// Passing simple data structures with the desired data
&lt;Nav
  cta={{ text: &quot;Buy the book!&quot;, href: &quot;https://url.to/buy-my-book&quot; }}
  menuItems={[
    { text: &quot;Home&quot;, href: &quot;/home&quot; },
    { text: &quot;About&quot;, href: &quot;/about&quot; },
    { text: &quot;Contact&quot;, href: &quot;/contact&quot; },
  ]}
  title=&quot;My Site&quot;
/&gt;

// Passing JSX elements directly
&lt;Nav
  cta={&lt;a href=&quot;https://url.to/buy-my-book&quot;&gt;Buy the book!&lt;/a&gt;}
  menuItems={
    &lt;&gt;
      &lt;li&gt;
        &lt;a href=&quot;/home&quot;&gt;Home&lt;/a&gt;
      &lt;/li&gt;

      &lt;li&gt;
        &lt;a href=&quot;/about&quot;&gt;About&lt;/a&gt;
      &lt;/li&gt;

      &lt;li&gt;
        &lt;a href=&quot;/contact&quot;&gt;Contact&lt;/a&gt;
      &lt;/li&gt;
    &lt;/&gt;
  }
  title={&lt;h1&gt;My Site&lt;/h1&gt;}
/&gt;
</code></pre>
<p>Even in such as simple example, we can start seeing some of the problems with
this approach: it creeps the component API with render props, it is not very
idiomatic, and it can quickly get worse as we continue adding some more
customization for each element. For example, we may later add specific props to
styling each of the items, title, and call-to-action components:
<code>menuItemStyle</code>, <code>titleStyle</code>, <code>ctaStyle</code>, and so on:</p>
<pre><code class="language-jsx">&lt;Nav
  cta={{ text: &quot;Buy the book!&quot;, href: &quot;https://url.to/buy-my-book&quot; }}
  ctaStyle={{ color: &quot;red&quot; }}
  ctaOnClick={() =&gt; alert(&quot;Thanks for buying the book!&quot;)}
  menuItems={[
    { text: &quot;Home&quot;, href: &quot;/home&quot; },
    { text: &quot;About&quot;, href: &quot;/about&quot; },
    { text: &quot;Contact&quot;, href: &quot;/contact&quot; },
  ]}
  menuItemStyle={{ color: &quot;blue&quot; }}
  onMenuItemClick={(href) =&gt; alert(`Navigating to ${href}`)}
  title=&quot;My Site&quot;
  titleStyle={{ color: &quot;green&quot; }}
/&gt;
</code></pre>
<p>Let’s try a different approach. One that resembles how HTML works and that is
supported out-of-the-box by React.</p>
<h2>Using <code>children</code> and dedicated components</h2>
<pre><code class="language-jsx">&lt;Nav&gt;
  &lt;Nav.Title&gt;My Site&lt;/Nav.Title&gt;

  &lt;Nav.Menu&gt;
    &lt;Nav.Menu.Item href=&quot;/&quot;&gt;Home&lt;/Nav.Menu.Item&gt;
    &lt;Nav.Menu.Item href=&quot;/about&quot;&gt;About&lt;/Nav.Menu.Item&gt;
    &lt;Nav.Menu.Item href=&quot;/contact&quot;&gt;Contact&lt;/Nav.Menu.Item&gt;
  &lt;/Nav.Menu&gt;

  &lt;Nav.CallToAction href=&quot;https://url.to/buy-my-book&quot;&gt;
    Buy the book!
  &lt;/Nav.CallToAction&gt;
&lt;/Nav&gt;
</code></pre>
<p>If you have done some React development, you probably know the <code>children</code> prop
is how React passes content down to components (for example <code>&lt;p&gt;Hola&lt;/p&gt;</code>, where
<code>p</code> is the component, and <code>Hola</code> is the value of the <code>children</code> prop).</p>
<p>The example above uses <code>children</code> and composition extensively to render the
desired UI. Instead of passing multiple props to the <code>Nav</code> component, we create
many small, dedicated components which may of course receive their own props.</p>
<p>As a result, this approach gives us a much more flexible and idiomatic API. If
we later need to add additional elements to the <code>Nav</code> component, we can do so
without changing the <code>Nav</code> component at all (following the <a href="https://en.wikipedia.org/wiki/Open%E2%80%93closed_principle">Open-Closed design
principle</a>).</p>
<p>On the other hand, using this technique comes with some drawbacks worth
mentioning:</p>
<ul>
<li>We have to make it clear that these dedicated components are only meant to be
used as children of the <code>Nav</code> component. We can do this by using the <code>Nav</code>
namespace, for example: <code>Nav.Title</code>, <code>Nav.Menu</code>, and <code>Nav.CallToAction</code>.</li>
<li>We must ensure the <code>Nav</code> component is flexible enough to handle the different
cases we might want to render. For example, if we want to make it possible to
render the <code>Nav.Menu</code> component either after or before the <code>Nav.CallToAction</code>
component, the styles should be sufficiently sophisticated to handle both
cases.</li>
</ul>
<h3>Possible implementation</h3>
<p>Pay attention to how we export the <code>Nav</code> component and its dedicated components.
That’s the secret sauce to namespace them and make it clear they are only meant
to be used as children of the <code>Nav</code> component.</p>
<pre><code class="language-jsx">const Nav = ({ children }) =&gt; {
  return &lt;nav&gt;{children}&lt;/nav&gt;;
};

const CallToAction = ({ children, href }) =&gt; {
  return &lt;a href={href}&gt;{children}&lt;/a&gt;;
};

const Menu = ({ children }) =&gt; {
  return &lt;ul&gt;{children}&lt;/ul&gt;;
};

const MenuItem = ({ children, href }) =&gt; {
  return (
    &lt;li&gt;
      &lt;a href={href}&gt;{children}&lt;/a&gt;
    &lt;/li&gt;
  );
};

const Title = ({ children }) =&gt; {
  return &lt;h1&gt;{children}&lt;/h1&gt;;
};

Menu.Item = MenuItem;

Nav.CallToAction = CallToAction;
Nav.Menu = Menu;
Nav.Title = Title;

export { Nav };
</code></pre>
<h2>Notes</h2>
<ul>
<li>A few weeks after starting to write this post, I received a newsletter from
<a href="https://kentcdodds.com/">Kent C. Dodds</a> featuring a React article. Coincidentally, the
content of <a href="https://epicreact.dev/soul-crushing-components/">the post</a> covered precisely this! So,
digging a little more, I found this pattern had been documented since a few
years ago (watch out <a href="https://www.youtube.com/watch?v=hEGg-3pIHlE">this video talk</a> from Ryan Florence at <em>Phoenix
ReactJS Conf</em> in 2017), and it is called <strong><em>Compound components</em></strong>.</li>
<li><a href="https://www.radix-ui.com/">Radix UI</a> uses this pattern extensively.</li>
<li>If you’re curious, I used this pattern to build the whole landing page for my
tddworkshop.com page. You can check the source code <a href="https://github.com/codecoolture/tddworkshop.com/blob/trunk/pages/en/index.tsx">here</a>.</li>
</ul>
<p>Happy hacking!</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Using the Builder pattern for creating test data with ease]]></title>
        <id>https://codecoolture.com/blog/builder-pattern-for-test-data</id>
        <link href="https://codecoolture.com/blog/builder-pattern-for-test-data"/>
        <updated>2022-11-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Make your test code look as appealing as your production code using a design pattern that reduces verbosity and favors expressiveness.]]></summary>
        <content type="html"><![CDATA[<h1>Using the Builder pattern for creating test data with ease</h1>
<p>If you have yet to hear about [software] design patterns, you may think of them
as reusable solutions for everyday problems that work for different contexts. Of
course, new design patterns appear now and then, but there is a <a href="https://en.wikipedia.org/wiki/Software_design_pattern#Classification_and_list">well-documented
core of patterns</a> that are popular and can be seen in many
object-oriented code bases. The <a href="https://en.wikipedia.org/wiki/Builder_pattern">Builder</a> pattern is one of them.</p>
<p>Although this pattern may come in handy in multiple situations, it is especially
helpful when creating test data. Tests for any medium-large-sized applications
often require us to create various objects, put them in a particular state, and
have relationships with other entities. That can be hard to do, especially if
the objects are complex and we need to create many of them. The Builder pattern
offers a solution to use a more semantic, domain-specific interface that makes
the process easier.</p>
<p>For example, imagine we are coding a software system to help manage an
automobile repair shop. Not surprisingly, we may find mechanics and cars.
Mechanics can be responsible for multiple vehicles, be on holiday, and have
different hourly salaries. The following tests verify that we cannot assign a
car to a mechanic under certain circumstances.</p>
<pre><code class="language-ts">import { Car, Mechanic } from &quot;@domain&quot;;

describe(&quot;POST /mechanics/{id}/cars&quot;, () =&gt; {
  it(&quot;does not add a new car if the mechanic is on holiday&quot;, async () =&gt; {
    const mechanic = new Mechanic({
      id: 1,
      name: &quot;Alice&quot;,
    });

    const today = new Date();

    const pto = new Pto({
      mechanic,
      startDate: startOfDay(today),
      endDate: endOfDay(today),
    });

    mechanic.ptos = [pto];

    await mechanicRepository.save(mechanic);

    const car = new Car({
      id: 1,
      make: &quot;Mazda&quot;,
      model: &quot;Mazda 3&quot;,
      year: 2021,
    });

    await carRepository.save(car);

    const response = await request(app)
      .post(`/mechanics/${mechanic.id}/cars`)
      .send({ carId: car.id });

    expect(response.status).toBe(400);
  });

  it(&quot;does not add a new car if the mechanic is working on five cars already&quot;, async () =&gt; {
    const mechanic = new Mechanic({ id: 1, name: &quot;Alice&quot; });

    mechanic.cars = [
      new Car({
        id: 1,
        make: &quot;Mazda&quot;,
        model: &quot;Mazda 2&quot;,
        year: 2021,
      }),
      new Car({
        id: 2,
        make: &quot;Mazda&quot;,
        model: &quot;Mazda 3&quot;,
        year: 2021,
      }),
      new Car({
        id: 3,
        make: &quot;Mazda&quot;,
        model: &quot;CX-30&quot;,
        year: 2021,
      }),
      new Car({
        id: 4,
        make: &quot;Mazda&quot;,
        model: &quot;MX-5&quot;,
        year: 2021,
      }),
      new Car({
        id: 5,
        make: &quot;Mazda&quot;,
        model: &quot;CX-60&quot;,
        year: 2021,
      }),
    ];

    await mechanicRepository.save(mechanic);

    const car = new Car({
      id: 6,
      make: &quot;Mazda&quot;,
      model: &quot;CX-9&quot;,
      year: 2021,
    });

    await carRepository.save(car);

    const response = await request(app)
      .post(`/mechanics/${mechanic.id}/cars`)
      .send({ carId: car.id });

    expect(response.status).toBe(400);
  });
});
</code></pre>
<p>As you may see in the code block above, creating all these objects by hand is
expensive and makes the whole test hard to read. Let’s try instead to use a
<code>MechanicBuilder</code> that makes the process easier while producing the same result.</p>
<pre><code class="language-ts">import { MechanicBuilder, CarBuilder } from &quot;@test/builders&quot;;

describe(&quot;POST /mechanics/{id}/cars&quot;, () =&gt; {
  it(&quot;does not add a new car if the mechanic is on holiday&quot;, async () =&gt; {
    const mechanic = await new MechanicBuilder()
      .onHoliday()
      .save(mechanicRepository);

    const car = await new CarBuilder().save(carRepository);

    const response = await request(app)
      .post(`/mechanics/${mechanic.id}/cars`)
      .send({ carId: car.id });

    expect(response.status).toBe(400);
  });

  it(&quot;does not add a new car if the mechanic is working on five cars already&quot;, async () =&gt; {
    const mechanic = await new MechanicBuilder()
      .withCars(5)
      .save(mechanicRepository);

    const car = await new CarBuilder().save(carRepository);

    const response = await request(app)
      .post(`/mechanics/${mechanic.id}/cars`)
      .send({ carId: car.id });

    expect(response.status).toBe(400);
  });
});
</code></pre>
<p>Reading the code above, we can clearly see the scenario we are creating for the
test. The builder reduces verbosity and makes the code more expressive while
favoring reusability for other test cases. Of course, we may keep adding methods
to the <code>MechanicBuilder</code> as new requirements appear, so we always have an
up-to-date, semantic interface to create <code>Mechanic</code> objects (and the same
applies for <code>Car</code> instances).</p>
<h2>Example of a Builder implementation using TypeScript</h2>
<p>Wondering how you can create that fancy builder above using TypeScript? 😏 As
with many things in software development, different paths may lead to the same
result, but this approach worked very well for me in the past.</p>
<p>The Builder pattern is considered a <em>creational pattern</em> since it helps us
create objects by removing all the complexity to instantiate them. So let’s
start by creating a generic <code>Builder&lt;T&gt;</code> interface that defines the two methods
all builders should implement: <code>build</code> (to return the object) and <code>save</code> (to
persist the object in the database). I usually add a third method, <code>with</code>, that
would allow us to pass an object with the properties we want to override. Still,
for the sake of simplicity, I will skip it in this example.</p>
<pre><code class="language-ts">export interface Builder&lt;T&gt; {
  build(): T;
  save(repository: Repository&lt;T&gt;): Promise&lt;T&gt;;
}
</code></pre>
<p>Then, we may create a <code>BaseBuilder&lt;T&gt;</code> abstract class that implements the
<code>Builder&lt;T&gt;</code> interface and provides a default implementation for both methods.
The <code>build</code> method will return the object, while the <code>save</code> method will return
the object and persist it in the database. Here, we use inheritance just for
code reusability.</p>
<pre><code class="language-ts">import { Builder } from &quot;@test/builders&quot;;

export abstract class BaseBuilder&lt;T&gt; implements Builder&lt;T&gt; {
  protected abstract entity: T;

  public build(): T {
    return this.entity;
  }

  public save(repository: Repository&lt;T&gt;): Promise&lt;T&gt; {
    return repository.save(this.entity);
  }
}
</code></pre>
<p>Finally, we can create the <code>MechanicBuilder</code> simply by extending
<code>BaseBuilder&lt;Mechanic&gt;</code> and providing all the additional methods.</p>
<pre><code class="language-ts">import { Mechanic } from &quot;@domain&quot;;
import { BaseBuilder, CarBuilder, PtoBuilder } from &quot;@test/builders&quot;;

export class MechanicBuilder extends BaseBuilder&lt;Mechanic&gt; {
  protected entity: Mechanic;

  constructor() {
    super();

    this.entity = new Mechanic({ id: 1, name: &quot;Alice&quot; });
  }

  public onHoliday(): this {
    this.entity.ptos = [
      new PtoBuilder().for(this.entity).on(new Date()).build(),
    ];

    return this;
  }

  public withCars(count: number): this {
    this.entity.cars = new Array(count)
      .fill(null)
      .map(() =&gt; new CarBuilder().build());

    return this;
  }
}
</code></pre>
<blockquote>
<p>Note how we return <code>this</code> in the <code>onHoliday</code> and <code>withCars</code> methods. That is
the <em>secret sauce</em> to making the Builder provide a <a href="https://en.wikipedia.org/wiki/Fluent_interface">fluent interface</a>
so that we can use it in the following way:</p>
</blockquote>
<pre><code class="language-ts">const mechanic = await new MechanicBuilder()
  .onHoliday()
  .withCars(5)
  .save(mechanicRepository);
</code></pre>
<p>Happy hacking!</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Adding an RSS feed to a Next.js site]]></title>
        <id>https://codecoolture.com/notes/rss-for-next-blog</id>
        <link href="https://codecoolture.com/notes/rss-for-next-blog"/>
        <updated>2022-09-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[This is the story of how I added RSS support for this blog.]]></summary>
        <content type="html"><![CDATA[<h1>Adding an RSS feed to a Next.js site</h1>
<p>Really Simple Syndication (<strong>RSS</strong>) has been a pretty popular format for
syndicating and publishing content on the web. Still, platforms don’t usually
provide an out-of-the-box solution to adopt it.</p>
<p>For Next.js projects, specifically, I’m sure there are probably thousands of
articles explaining how to do it (and probably a handful of <code>npm</code> packages,
too!), but in this post, I will try to outline my own approach to this problem
to add <a href="/feed.xml">RSS capabilities for this very same blog</a>.</p>
<h2>How to build the RSS feed</h2>
<p>The only thing I didn’t want to do was study the
<a href="https://validator.w3.org/feed/docs/rss2.html">RSS</a> or
<a href="https://validator.w3.org/feed/docs/atom.html">Atom</a> spec myself to know how to
create a valid document. For that reason, I browsed the web looking for a
well-maintained <code>npm</code> package that could help me externalize part of the work.</p>
<p><a href="https://github.com/jpmonette/feed"><code>jpmonette/feed</code></a> ticked all the boxes (some
recent commits, a good amount of stars, and TypeScript support), so I installed
the package and started coding the <code>RssFeedGenerator</code> class.</p>
<p>The <code>RssFeedGenerator</code> is a simple TypeScript class that receives an array of
paths and gets all the posts that live there. Then, it makes minor adjustments
(flat the collection of posts, order by date) and uses the <code>jpmonette/feed</code>
package to return a valid atom feed string. Since this blog is open-sourced, you
may see the actual code for this class in
<a href="https://github.com/codecoolture/codecoolture.com/blob/fdcbcd2ff6307f5fb42ec463b2547e572edf8047/bin/rss/RssFeedGenerator.ts"><code>codecoolture/codecoolture.com</code></a>.</p>
<pre><code class="language-ts">export class RssFeedGenerator {
  constructor(private paths: string[]) {}

  public async generate(): Promise&lt;string&gt; {
    const feed = new Feed({
      /* Add some feed configuration */
    });

    const allArticles = await Promise.all(
      this.paths.map(async (path) =&gt; {
        const repository = await MarkdownRepository.fromDirectory(path);

        return repository.all({ drafts: false });
      }),
    );

    const articlesFromNewestToOldest = orderBy(allArticles.flat(), &quot;date&quot;, [
      &quot;desc&quot;,
    ]);

    for (const article of articlesFromNewestToOldest) {
      feed.addItem({
        /* Add properties for each item */
      });
    }

    return feed.atom1();
  }
}
</code></pre>
<p>The <code>RssFeedGenerator</code> does not know by itself what the paths are, so it expects
them to be injected during initialization. This decision was driven by my
approach using test-driven development since I wanted to create different
fixtures to test different scenarios without relying on the actual production
data (posts may change title, date, or even get deleted!).</p>
<p>Design-wise, injecting the RSS feed generator would also be desirable, so we
could rely on our own abstractions rather than having this code coupled to a
third-party library. Still, the use case is so simple that I decided to skip the
extra work (I hope it does not bite me in the future!).</p>
<h2>How to integrate <code>RssFeedGenerator</code> with Next.js</h2>
<p>At this point, this site uses <code>next export</code> to build a static website.
Therefore, I couldn’t rely on some of the more advanced Next.js features such as
<a href="https://nextjs.org/docs/api-routes/introduction">API Routes</a> or even
<a href="https://nextjs.org/docs/advanced-features/middleware">middlewares</a>. So instead,
I decided to integrate the RSS feed generation within the Next.js build by
adding a new <code>npm script</code> that executes <code>bin/rss/index.ts</code> (a TypeScript script)
and creates a <code>RssFeedGenerator</code> instance with the right content paths, using
its output to save a file inside the Next.js <code>public/</code> folder. This is what the
script and the new build command look like.</p>
<pre><code class="language-diff">-    &quot;build&quot;: &quot;next build&quot;,
+    &quot;build&quot;: &quot;yarn build:rss &amp;&amp; next build&quot;,
+    &quot;build:rss&quot;: &quot;NODE_ENV=development yarn ts:exec ./bin/rss/index.ts&quot;,
</code></pre>
<pre><code class="language-ts">import { writeFile } from &quot;node:fs/promises&quot;;
import { join } from &quot;node:path&quot;;
import { getConfig } from &quot;../../config&quot;;
import { RssFeedGenerator } from &quot;./RssFeedGenerator&quot;;

(async function run() {
  const generator = new RssFeedGenerator([
    getConfig().writing.articles,
    getConfig().writing.notes,
  ]);

  const feed = await generator.generate();

  await writeFile(join(__dirname, &quot;../../public/feed.xml&quot;), feed);
})();
</code></pre>
<p>With all these pieces now working together, new deployments of this site will
always create a valid RSS feed that can be found at <a href="/feed.xml"><code>/feed.xml</code></a>,
keeping the static nature of the website and leveraging a more sophisticated
build process.</p>
<p>What do you think if we make good use of this new feature and subscribe to the
RSS feed? 😃</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #9: Q3 2021]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q3-2021</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q3-2021"/>
        <updated>2021-10-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Colección de enlaces interesantes recopilados durante el tercer trimestre de 2021.]]></summary>
        <content type="html"><![CDATA[<h1>Quarterlinks #9: Q3 2021</h1>
<h2>Career Framework</h2>
<p>Una buena parte de este tercer trimestre la dediqué a diseñar una primera
iteración del career framework para el equipo de ingeniería de PrivacyCloud.
Muchas empresas tecnológicas tienen públicos estos documentos así que, como no
podía ser de otra manera, aproveché la oportunidad para leer un montón de ellos,
aprender y tratar de implementar uno que recogiese con acierto nuestras
expectativas de cada rol (siempre, claro, adaptadas al propio contexto y cultura
del equipo y la empresa).</p>
<p>Además de un índice muy útil como <a href="https://www.progression.fyi/">progression.fyi</a>, os dejo
por aquí los cinco ejemplos que más me han gustado (tanto por su filosofía, como
por su explicación y diseño de cada camino y nivel).</p>
<ul>
<li><strong><a href="https://career-ladders.dev/">Career Ladders by Sarah Drasner</a></strong>: es un punto de partida
fantástico para diseñar un career ladder para un equipo de ingeniería: define
cada rol con 4-5 puntos que ejemplifican los comportamientos y expectativas,
huye de la trampa de un checklist y explica con bastante acierto cómo encaja
el rol de Tech Lead (en mi experiencia, muy ambiguo) en todo esto.</li>
<li><strong><a href="https://medium.com/building-carta/engineering-levels-at-carta-d33db2a55a20">Engineering levels at Carta</a></strong>: lo más interesante son las partes
donde explican el razonamiento y filosofía detrás de su framework (<em>fairness</em>,
<em>compensation</em>, <em>career progression</em>).</li>
<li><strong><a href="https://dropbox.github.io/dbx-career-framework/">Dropbox Engineering Career Framework</a></strong>: su definición de impacto
y cómo articulan todo el framework alrededor de este concepto.</li>
<li><strong><a href="https://developers.soundcloud.com/blog/engineering-levels">Engineering Levels at SoundCloud</a></strong>: es bastante conciso y me
ha ayudado a no irme por las ramas (<em>keep it simple</em>).</li>
<li><strong><a href="https://docs.google.com/spreadsheets/d/131XZCEb8LoXqy79WWrhCX4sBnGhCM1nAIz4feFZJsEo/edit#gid=0">CircleCI Engineering Competency Matrix</a></strong>: es, de los cinco, el
que mayor exhaustividad muestra a la hora de definir las compentencias en
diferentes niveles. Personalmente, no he seguido su enfoque, pero me ha
ayudado a perfilar algunas ideas.</li>
</ul>
<blockquote>
<p>Si quieres echar un vistazo al Career Framework de PrivacyCloud,
<a href="mailto:sergio@codecoolture.com">escríbeme</a>, cuéntame un poco sobre ti y
estaré encantado de enviarte una copia!</p>
</blockquote>
<h2>🛠 Código</h2>
<ul>
<li><strong><a href="https://github.com/searls/todo_or_die"><code>searls/todo_or_die</code></a></strong>: no sé si sería buena idea utilizarlo en una
proyecto <em>real</em> pero me ha encantado la idea: ¿qué te parece si esos <code>TODO</code>
que NUNCA resuelves empiezan a lanzar excepciones pasados N días? 😄</li>
</ul>
<pre><code class="language-ruby">class UsersController &lt; ApiController
  TodoOrDie(&quot;delete after JS app has propagated&quot;, by: &quot;2019-02-04&quot;)
  def show
    redirect_to root_path
  end
end
</code></pre>
<ul>
<li><strong><a href="https://github.com/radix-ui/colors"><code>radix-ui/colors</code></a></strong>: me gusta crear interfaces usables, accesibles
y bonitas a pesar de no tener conocimientos de diseño (más allá de los
adquiridos con la experiencia), así que recursos como este siempre me parecen
oro. Radix UI tiene un módulo de colores que puedes instalar de manera
independiente y que, más allá de tener unas escalas muy bonitas, tiene una
documentación ❤️ que te ayuda a decidir qué tonos tienes que utilizar en cada
momento (como fondo cuando el elemento tiene el <code>:hover</code>, como borde cuando el
elemento no es interactivo, como color de texto, etc.). Simplemente funciona.</li>
</ul>
<h2>🎱 Bola extra: Love, Death &amp; Robots</h2>
<p>Netflix produce esta pequeña joya de animación. Son 2 temporadas con capítulos
muy cortos (algunos no duran más que unos pocos minutos) que muestran diferentes
distopías donde, cada vez más, los humanos tienen que compartir su vida con
avances tecnológicos de todo tipo.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #8: Q2 2021]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q2-2021</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q2-2021"/>
        <updated>2021-07-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Colección de enlaces interesantes que disfruté durante el segundo trimestre de 2021.]]></summary>
        <content type="html"><![CDATA[<h1>Quarterlinks #8: Q2 2021</h1>
<p>Qué mejor manera de arrancar el verano que con una buena colección de enlaces y
recursos interesantes 😃</p>
<h2>💻 Blogposts</h2>
<ul>
<li><strong><a href="https://www.elidedbranches.com/2021/06/an-incomplete-list-of-skills-senior.html?m=1">An incomplete list of skills senior engineers need, beyond
coding</a></strong>: típico ejemplo de post cortito pero con mucho contenido
para reflexionar. Y es que medir el <em>seniority</em> únicamente por las habilidades
técnicas es simplificar demasiado el impacto que <del>podemos</del> debemos tener.</li>
<li><strong><a href="https://sive.rs/about">About Derek Sivers</a></strong>: bueno, no es exactamente un blogpost pero...
esta página en la web de Derek Sivers me ha gustado mucho, especialmente
después de haber leído su libro (Anything You Want -como comenté en el
<a href="/notes/quarterlinks-q1-2021/">anterior Quarterlinks</a>). Sin duda, Derek es una
persona con las ideas muy claras y una manera de entender el trabajo (y la
vida) muy interesantes. Revisando también
<a href="https://sive.rs/book">su lista de libros favoritos</a>, me he encontrado con
varios libros que he leído también en los últimos meses: <em>The Obstacle Is the
Way</em> de Ryan Holiday, <em>Mindfulness in Plain English</em> de Bhante Gunaratana o
<em>Meditations</em> de Marco Aurelio.</li>
<li><strong><a href="https://world.hey.com/joaoqalves/i-could-build-this-during-the-weekend-aa093c5e">I could build this during the weekend</a></strong>: ¡culpable! Sirva este
post como recordatorio de todas las complejidades subyacentes a la hora de
desarrollar un negocio y un producto digital.</li>
<li><strong><a href="https://www.galiglobal.com/blog/2021/20210313-The-principal-role.html">My thoughts about the Principal role</a></strong>: es un rol que aparece
en empresas de gran tamaño y del que no había leído (aún) demasiado.</li>
<li><strong><a href="https://evertpot.com/jwt-is-a-bad-default/">JWT should not be your default for sessions</a></strong>: <em>food for thought</em>! Y
es que a veces las opciones que asumimos por defecto pueden tener <em>trade-offs</em>
de los que no estamos al tanto.</li>
<li><strong><a href="https://nerds.ontruck.com/defining-the-value-proposition-on-a-co-creative-dynamic-with-sales-product-9ccf3026414d">Defining the Value Proposition on a co-creative dynamic with Sales &amp;
Product</a></strong>: me ha gustado este post de Álvar Montes explicando las
dinámicas que facilitó en un offsite de los equipos de ventas y producto en
OnTruck.</li>
</ul>
<h2>🛠 Código</h2>
<ul>
<li><strong><a href="https://github.com/google/zx"><code>google/zx</code></a></strong>: este proyecto open source de Google me ha parecido
súper interesante. Últimamente, todos mis scripts ya los escribía con Node y
<code>zx</code> propociona abstracciones <em>amigables</em> para lidiar con funciones habituales
de más bajo nivel.</li>
</ul>
<h2>📚 Libros</h2>
<ul>
<li><strong><a href="https://www.goodreads.com/book/show/45303387-an-elegant-puzzle">An Elegant Puzzle: Systems of Engineering Management</a></strong>: en este
libro, <a href="https://lethain.com/">Will Larson</a> (Digg, Stripe, Uber) condensa mucha
de su experiencia liderando equipos de ingeniería en forma de anécdotas,
fórmulas, estrategias, prácticas y consejos. Es un libro de múltiples
lecturas. De momento, he terminado una primera de principio a fin, pero voy a
tenerlo bien cerquita para consultarlo cuando me enfrente a próximos retos.</li>
</ul>
<h2>🎱 Bola extra: El método Kominsky</h2>
<p>22 capítulos de menos de 30 minutos cada uno (¡se ven como nada!), repartidos en
3 temporadas. Está disponible en Netflix, y está protagonizada por Michael
Douglas en el papel de un profesor de interpretación que otrora tuvo poco éxito
como actor. La verdad es que me he reído mucho con <a href="https://www.filmaffinity.com/es/film813870.html">El método
Kominsky</a>. En cierto modo ha sido como ver a Hank Moody, de
Californication, 30 y pico años más viejo (y con un punto menos canalla).</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #7: Q1 2021]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q1-2021</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q1-2021"/>
        <updated>2021-04-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Colección de enlaces interesantes que disfruté durante el pasado trimestre.]]></summary>
        <content type="html"><![CDATA[<h1>Quarterlinks #7: Q1 2021</h1>
<p>Como de costumbre, vamos allá con algunos enlaces interesantes del pasado
trimestre.</p>
<h2>💻 Blogposts</h2>
<ul>
<li><strong><a href="https://www.eferro.net/2021/02/basal-cost-of-software.html">Basal Cost of Software</a></strong>: Edu Ferro nos habla del coste que
tiene para el sistema el acumulado de funcionalidad a medida que avanza la
vida de un producto.</li>
<li><strong><a href="https://www.eferro.net/2021/01/small-batches-for-win-continuous.html">Small batches for the win / Continuous Delivery</a></strong>: uno de
los conceptos clave para entender (e implementar) <em>continuous delivery</em>:
trabajar en pasos pequeñitos, pero de manera continua (de esa manera, podemos
obtener feedback más rápido a la vez que minimizamos los riesgos).</li>
<li><strong><a href="https://sahillavingia.com/work">No Meetings, No Deadlines, No Full-Time Employees</a></strong>: muy
interesante conocer la filosofía de trabajo en <a href="https://gumroad.com/">Gumroad</a>, contada en
primera persona por su CEO: Sahil Lavingia.</li>
<li><strong><a href="https://newsletter.bringthedonuts.com/p/what-makes-a-strong-product-culture">What Makes A Strong Product Culture?</a></strong>: empoderar equipos
de producto... si llevas siguiendo esta sección durante los últimos meses,
habrás visto que siempre cae una pieza sobre este tema.</li>
<li><strong><a href="https://startup-cto.net/10-bad-typescript-habits-to-break-this-year/">10 bad TypeScript habits to break this year</a></strong>: soy culpable de
alguno de los malos hábitos que se detallan en el artículo. Desde hace meses
estoy luchando activamente por evitar al máximo los puntos 4 y 5.</li>
<li><strong><a href="https://simpleshapes.io/articles/your-engineering-team-is-too-big/">Your engineering team is (probably) too big</a></strong>: quizás (?) el enlace
más controvertido. Siempre es interesante recordar que es posible conseguir
muchas cosas con equipos relativamente pequeños (en el artículo se cita a
Notion, con más de 1 millón de usuarios, siendo una empresa de 10 personas).</li>
</ul>
<h2>📚 Libros</h2>
<p>Os dejo un par de libros que me han parecido muy interesantes y que se leen
rápidamente:</p>
<ul>
<li><strong><a href="https://www.amazon.es/dp/B078X4HKS9">Measure What Matters</a></strong>: John Doerr, que trabajó durante buena parte
de su carrera junto a <a href="https://en.wikipedia.org/wiki/Andrew_Grove">Andy Grove</a>, nos explica OKRs a través de la
experiencia de múltiples empresas que lo han adoptado de manera exitosa
(Google, YouTube, Gates Foundation).</li>
<li><strong><a href="https://www.amazon.es/Anything-You-Want-Lessons-Entrepreneur-ebook/dp/B013XUNUAA">Anything You Want</a></strong>: Derek Sivers nos cuenta, en primera persona,
su aventura creando CD Baby, una empresa que en el año 1997 empezó a vender
música por Internet de artistas independientes (cuando sólo se podía acceder
al circuito a través de las grandes distribuidoras). Una ejecución brillante y
una manera poco convencional de entender la empresa y el trabajo.</li>
</ul>
<h2>🎱 Bola extra: Leftovers</h2>
<p>Tenía en el radar esta <a href="https://www.filmaffinity.com/es/film349114.html">serie de HBO</a> desde hace tiempo, pero no fue
hasta finales de 2020 cuando me lancé a empezarla. De digestión lenta, quizás el
final es un tanto acelerado para el ritmo habitual de la serie, pero yo la
disfruté tanto que terminé por votarla con un 9 en FilmAffinity.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Uncovering and conquering async bugs: A trick to testing undesired effects]]></title>
        <id>https://codecoolture.com/blog/testing-the-unexpected</id>
        <link href="https://codecoolture.com/blog/testing-the-unexpected"/>
        <updated>2021-03-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[A reasonable approach to test React components with unexpected async effects.]]></summary>
        <content type="html"><![CDATA[<h1>Uncovering and conquering async bugs: A trick to testing undesired effects</h1>
<p>Imagine you are coding a new React component to upload a file. The component
will receive a callback to notify the app if the upload has been or has not been
successful. You may end with something similar to:</p>
<pre><code class="language-tsx">/**
 * We will use the `executor` function to simulate different
 * scenarios from our tests.
 */
function UploadButton({ executor, onSuccess }) {
  return (
    &lt;button
      type=&quot;button&quot;
      onClick={async () =&gt; {
        await executor();

        onSuccess();
      }}
    &gt;
      Upload
    &lt;/button&gt;
  );
}
</code></pre>
<p>To test the most simple scenario, that the <code>&lt;UploadButton /&gt;</code> component uses the
callback once the upload is completed, we can rely on the standard approach:</p>
<pre><code class="language-tsx">it(&quot;uses the callback to notify that the upload completed&quot;, async () =&gt; {
  const spy = jest.fn();

  render(&lt;UploadButton executor={success} onSuccess={spy} /&gt;);

  user.click(screen.getByText(&quot;Upload&quot;));

  await waitFor(() =&gt; {
    expect(spy).toHaveBeenCalledTimes(1);
  });
});
</code></pre>
<p>But things are more complicated if we want to ensure that the <code>onSuccess</code>
callback is not executed if something unexpected happens and the process fails.
The initial and most naive implementation might be to assure that the spy is
never called when using the failing executor:</p>
<pre><code class="language-tsx">it(&quot;does not use the callback if something goes wrong&quot;, async () =&gt; {
  const spy = jest.fn();

  render(&lt;UploadButton executor={fail} onSuccess={spy} /&gt;);

  user.click(screen.getByText(&quot;Upload&quot;));

  await waitFor(() =&gt; {
    expect(spy).toHaveBeenCalledTimes(0);
  });
});
</code></pre>
<p><strong>Even if it passes, the test is not checking that the spy never gets called</strong>.
Since the executor is an asynchronous process, and the spy starts with zero
calls, the expectation is valid immediately. You can spot this by replacing
<code>executor={fail}</code> with <code>executor={success}</code> --that’s the kind of change that
should make the test have a different result, but it continues passing!</p>
<p>To test this scenario, we need to come up with a different approach:</p>
<pre><code class="language-tsx">it(&quot;does not use the callback if something goes wrong&quot;, async () =&gt; {
  const asyncRender = new Promise&lt;undefined&gt;((resolve, reject) =&gt; {
    render(&lt;UploadButton executor={fail} onSuccess={reject} /&gt;);

    user.click(screen.getByText(&quot;Upload&quot;));

    setTimeout(resolve, 0);
  });

  await expect(asyncRender).resolves.toBeUndefined();
});
</code></pre>
<p>By embracing the asynchronous nature of this problem, we can wrap the rendering
within a promise and use its reject function as the <code>onSuccess</code> callback.
Remember that promises execute immediately but return a delayed response. To
give some room for the component to fail, I use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#zero_delays">setTimeout</a>
trick to force the process to complete pending tasks from the queue.</p>
<p>Now, <code>asyncRender</code> should always resolve (with an <code>undefined</code> value). If it does
not, our component is having issues handling the <code>onSuccess</code> callback and
calling it even when the upload fails (since it is what the failing executor
does). If you change <code>executor={fail}</code> to <code>executor={success}</code>, you may see the
result keeps consistent, and the test fails.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #6: Q4 2020]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q4-2020</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q4-2020"/>
        <updated>2021-01-06T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<h1>Quarterlinks #6: Q4 2020</h1>
<p>Vamos con la colección de recursos interesantes leídos durante octubre,
noviembre y diciembre del pasado (¡por fin!) 2020.</p>
<h2>💻 Blogposts</h2>
<ul>
<li><strong><a href="https://gerireid.com/forms.html">Forms best practice</a></strong>: esta guía escrita por Geri Reid se ha
convertido en mi sitio de referencia a la hora de construir formularios en
aplicaciones web. Hay dos cosas que me gustan especialmente: 1) que está
repleta de opiniones 2) que todas las opiniones están contrastadas con
diversos estudios y ejemplos del mundo real.</li>
<li><strong><a href="https://medium.com/packlinkeng/packlink-engineering-vision-for-2021-c8f10eb369cf">Packlink engineering vision for 2021</a></strong>: quienes sigáis esta
serie de posts de manera habitual sabréis que me gusta mucho leer artículos
donde empresas tecnológicas publican datos de su día a día, tecnologías que
utilizan, objetivos, estrategia, etc. Pues este artículo escrito por Packlink
tiene un poco de todo lo anterior.</li>
<li><strong><a href="https://lethain.com/good-engineering-strategy-is-boring/">Write five, then synthesize: good engineering strategy is
boring</a></strong>: muy relacionado con el artículo anterior, aquí se
reflexiona sobre cómo escribir una buena estrategia, por qué es importante y
qué primeros pasos podemos dar para arrancar con todo ello (en forma de
heurístico).</li>
<li><strong><a href="https://adamfaliq.com/2020/10/28/write-well/">How to Write Well: 4 Steps to Improve Your Writing</a></strong>: y como la
cosa va de escribir... lo suyo es hacerlo lo mejor posible, ¿no?</li>
<li><strong><a href="https://svpg.com/dual-track-agile/">Dual-Track Agile</a></strong>: no es el artículo más completo para
explicar dual-track pero sí es una buena introducción (además de ser,
posiblemente, la primera referencia escrita). Sin ser perfecto, es un marco de
trabajo que puede funcionar a la hora de construir un equipo de producto donde
las diferenes patas de la organización (product management, product design,
engineering) se sientan representadas y con libertad para moverse entre tareas
de diferentes naturalezas.</li>
</ul>
<h2>🎙 Podcasts</h2>
<ul>
<li><strong><a href="https://open.spotify.com/episode/2Py63SXJ7yhe18Wxuf9TKK?si=U_onblSoQUSLu9L0s0BvLA">Producto desde el minuto 0, con Javier Escribano</a></strong>: me ha gustado
mucho escuchar a <a href="https://www.javierescribano.me/">Javier Escribano</a> explicar el proceso de
desarrollo de producto en OnTruck. Además, con algún ejemplo concreto de cómo
es el proceso de conceptualización de una funcionalidad.</li>
<li><strong><a href="https://thebigbranchtheorypodcast.github.io/post/product-teams-edu-ferro/">Product Teams con Edu Ferro</a></strong>: siempre es un gusto escuchar a
<a href="https://www.eferro.net/">Edu Ferro</a> hablar de tecnología y desarrollo de
software. ¿Que os podéis encontrar? Entrega continua de software, desarrollo
de producto, excelencia técnica... en definitiva, 1 hora y 40 minutos muy bien
invertidos 🙂</li>
</ul>
<h2>🃏 Comodín</h2>
<ul>
<li><strong><a href="https://www.notion.so/How-Notion-Uses-Notion-616f41d2f5124f3185cf1c36d267c07e">How Notion Uses Notion</a></strong>. Vale. Lo reconozco. Este artículo NO lo
leí durante el último trimestre de 2020 pero se me olvidó compartirlo en su
momento 🤦‍♂️ Es un artículo muy meta donde Notion explica qué uso hace de su
plataforma y cómo organizan la información. Yo me he cogido unos cuantos
trucos. Especialmente sobre su gestión de la documentación.</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Un acercamiento sencillo a feature flags en una aplicación React con TypeScript]]></title>
        <id>https://codecoolture.com/blog/feature-flags-con-react-typescript</id>
        <link href="https://codecoolture.com/blog/feature-flags-con-react-typescript"/>
        <updated>2020-12-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[En esencia, una feature flag es un interruptor que nos permite activar o desactivar una funcionalidad concreta bajo una serie de condiciones. En este artículo me gustaría compartir una implementación sencilla en React, utilizando TypeScript.]]></summary>
        <content type="html"><![CDATA[<h1>Un acercamiento sencillo a feature flags en una aplicación React con TypeScript</h1>
<p>Aunque ya he escrito en otras ocasiones sobre feature flags y como su uso nos
puede ayudar a alcanzar un flujo de entrega continua, en este artículo me
gustaría compartir una implementación sencilla en React utilizando TypeScript.</p>
<p>En esencia, una feature flag es un interruptor que nos permite activar o
desactivar una funcionalidad concreta bajo una serie de condiciones. Los tipos
de condiciones pueden ser muy variados: entorno de ejecución de la aplicación,
tipo de usuaria, porcentaje de tráfico, etc. Además, el cálculo de esa condición
puede realizarse dentro de la propia aplicación, o bien delegarse en otro
sistema.</p>
<p>Este concepto posibilita, entre otras cosas, desacoplar nuestro repositorio del
proceso de entrega de software. Siempre y cuando nuestras funcionalidades
incompletas estén protegidas bajo una feature flag, podremos integrar
continuamente nuestros cambios en la rama principal (aunque eso implique su
despliegue a producción o cualquier otro entorno).</p>
<h2>Publicando feature flags</h2>
<p>El primer paso para comenzar a utilizar feature flags es definirlas en algún
sitio. Aunque existan servicios específicamente creados para trabajar con ellas
(que, además, ofrecen flujos y procesos mucho más refinados), yo siempre
recomiendo comenzar con un enfoque humilde, gestionando las feature flags
directamente en la aplicación. En este caso, vamos a crear un módulo que exporte
las diferentes feature flags y una función para obtener su estado:</p>
<pre><code class="language-tsx">export const Features = {
  newSettingsPage: () =&gt; process.env.NODE_ENV === &quot;development&quot;,
};
</code></pre>
<p>La única razón de asociar una función a la feature flag en lugar de directamente
un booleano es dotarle de cierta flexibilidad (realmente, sería incluso más
interesante hacer que la función devolviese una promesa -de esa manera,
estaríamos cubriendo el caso en el que, para calcular el valor de una feature
flag, tuviésemos que realizar una petición a un servicio externo).</p>
<h2>Integrando la aplicación React con las feature flags</h2>
<p>Ahora que ya tenemos un módulo encargado de publicar las feature flags de la
aplicación, es hora de hacerlo accesible desde los componentes React.</p>
<p>El enfoque más directo, sería importar el módulo desde las diferentes páginas o
componentes que lo utilicen y realizar después las operaciones para
mostrar/ocultar alguna parte de la interfaz. Aunque este enfoque funcionaría
estaríamos creando una dependencia no explícita entre nuestros diferentes
componentes y un elemento global (el módulo de <code>Features</code>) lo que hará que
probar nuestros componentes en cada uno de los estados sea más complejo.</p>
<p>Vamos a verlo con un ejemplo:</p>
<pre><code class="language-tsx">import { Features } from &quot;../lib/Features&quot;;

export function Menu() {
  return (
    &lt;nav&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;a href=&quot;/dashboard&quot;&gt;Dashboard&lt;/a&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;a href=&quot;/profile&quot;&gt;Profile&lt;/a&gt;
        &lt;/li&gt;

        {Features.newSettingsPage() &amp;&amp; (
          &lt;li&gt;
            &lt;a href=&quot;/settings&quot;&gt;Settings&lt;/a&gt;
          &lt;/li&gt;
        )}
      &lt;/ul&gt;
    &lt;/nav&gt;
  );
}
</code></pre>
<p>En esta implementación, <code>Menu</code> utiliza directamente el módulo de <code>Features</code> para
saber si tiene que mostrar o no la opción de ajustes. A la hora de probar este
componente, tenemos que tener en cuenta esta dependencia y utilizar un <em>stub</em>
para poder ajustarlo a ambos escenarios:</p>
<pre><code class="language-tsx">/**
 * @jest-environment jsdom
 */

import { render, screen } from &quot;@testing-library/react&quot;;
import { Features } from &quot;../lib/Features&quot;;
import { Menu } from &quot;./Menu&quot;;

describe(&quot;Menu&quot;, () =&gt; {
  it(&quot;doesn&#39;t show Settings if the feature is disabled&quot;, async () =&gt; {
    render(&lt;Menu /&gt;);

    expect(screen.queryByText(&quot;Settings&quot;)).toBeNull();
  });

  it(&quot;shows Settings if the feature is enabled&quot;, async () =&gt; {
    jest.spyOn(Features, &quot;newSettingsPage&quot;).mockImplementationOnce(() =&gt; true);

    render(&lt;Menu /&gt;);

    expect(screen.queryByText(&quot;Settings&quot;)).not.toBeNull();
  });
});
</code></pre>
<p>Los stubs (o test doubles en general) son recursos muy útiles pero me gusta
reservar su uso para situaciones donde no tengo ninguna otra opción más
idiomática para probar el sujeto bajo test. En este caso, lo ideal sería
convertir esa dependencia no explícita en algo que pudiésemos controlar desde el
exterior, utilizando inyección de dependencias. En React, tendríamos varias
opciones para conseguirlo. Veamos un par de ellas.</p>
<h3>Obtener las feature flags a través de una prop</h3>
<p>Por ejemplo, utilizando una prop <code>features</code> para poder recibir el objeto
completo de feature flags. El problema con este enfoque es que podría haber
muchos componentes intermedios que necesiten propagar esta prop sin necesidad de
utilizarla. Este fenómeno se denomina
<a href="https://kentcdodds.com/blog/prop-drilling">Prop Drilling</a> y, aunque no es malo
<em>per se</em>, puede convertirse en algo difícil de gestionar cuando nuestra
aplicación crezca en número de componentes.</p>
<pre><code class="language-tsx">import { Features } from &quot;../lib/Features&quot;;

export function Menu({ features }: { features: typeof Features }) {
  return (
    &lt;nav&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;a href=&quot;/dashboard&quot;&gt;Dashboard&lt;/a&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;a href=&quot;/profile&quot;&gt;Profile&lt;/a&gt;
        &lt;/li&gt;

        {features.newSettingsPage() &amp;&amp; (
          &lt;li&gt;
            &lt;a href=&quot;/settings&quot;&gt;Settings&lt;/a&gt;
          &lt;/li&gt;
        )}
      &lt;/ul&gt;
    &lt;/nav&gt;
  );
}
</code></pre>
<p>Ahora que el componente <code>Menu</code> obtiene la información de las feature flags a
través de una prop, podemos ajustar los diferentes escenarios para las pruebas
sin necesidad de utilizar test doubles:</p>
<pre><code class="language-tsx">/**
 * @jest-environment jsdom
 */

import { render, screen } from &quot;@testing-library/react&quot;;
import { Menu } from &quot;./Menu&quot;;

describe(&quot;Menu&quot;, () =&gt; {
  it(&quot;doesn&#39;t show Settings if the feature is disabled&quot;, async () =&gt; {
    render(&lt;Menu features={{ newSettingsPage: () =&gt; false }} /&gt;);

    expect(screen.queryByText(&quot;Settings&quot;)).toBeNull();
  });

  it(&quot;shows Settings if the feature is enabled&quot;, async () =&gt; {
    render(&lt;Menu features={{ newSettingsPage: () =&gt; true }} /&gt;);

    expect(screen.queryByText(&quot;Settings&quot;)).not.toBeNull();
  });
});
</code></pre>
<h3>Obtener las feature flags a través de la API de contextos</h3>
<p>Bien utilizada, la
<a href="https://reactjs.org/docs/context.html">API de contextos de React</a> puede servir
como un contenedor de inyección de dependencias que permita aislar a los
componentes padre de las dependencias concretas de sus componentes hijo. En este
caso, vamos a crear un nuevo contexto que publique las feature flags disponibles
dentro de la aplicación y que permita acceder a ellas a través de un hook
concreto, <code>useFeatures</code>.</p>
<p>Lo primero, es definir el propio contexto encargado de devolver las feature
flags existentes. Junto a él, también definiremos el hook que se utilizará
después desde nuestros componentes. Este último es una simple capa de
abstracción que centraliza la lógica común de acceso.</p>
<pre><code class="language-tsx">import { createContext, useContext } from &quot;react&quot;;

export const Features = {
  newSettingsPage: () =&gt; process.env.NODE_ENV === &quot;development&quot;,
};

export const FeaturesContext = createContext(Features);

export function useFeatures() {
  return useContext(FeaturesContext);
}
</code></pre>
<p>Los contextos en React se crean con un valor por defecto. En caso de que no
exista ningún proveedor que sobrescriba el valor para el contexto, nuestros
componentes recibirán ese valor al acceder a él. En este caso, hemos creado el
contexto utilizando como valor por defecto el propio objeto exportado por
<code>Features</code>.</p>
<pre><code class="language-tsx">import { useFeatures } from &quot;../lib/Features&quot;;

export function Menu() {
  const features = useFeatures();

  return (
    &lt;nav&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;a href=&quot;/dashboard&quot;&gt;Dashboard&lt;/a&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;a href=&quot;/profile&quot;&gt;Profile&lt;/a&gt;
        &lt;/li&gt;

        {features.newSettingsPage() &amp;&amp; (
          &lt;li&gt;
            &lt;a href=&quot;/settings&quot;&gt;Settings&lt;/a&gt;
          &lt;/li&gt;
        )}
      &lt;/ul&gt;
    &lt;/nav&gt;
  );
}
</code></pre>
<p>Ahora que nuestro componente <code>Menu</code> utiliza el nuevo contexto, sólo necesitamos
envolver el componente en diferentes proveedores cuando queramos probar
distintos escenarios:</p>
<pre><code class="language-tsx">/**
 * @jest-environment jsdom
 */

import { render, screen } from &quot;@testing-library/react&quot;;
import { FeaturesContext } from &quot;../lib/Features&quot;;
import { Menu } from &quot;./Menu&quot;;

describe(&quot;Menu&quot;, () =&gt; {
  it(&quot;doesn&#39;t show Settings if the feature is disabled&quot;, async () =&gt; {
    render(
      &lt;FeaturesContext.Provider value={{ newSettingsPage: () =&gt; false }}&gt;
        &lt;Menu /&gt;
      &lt;/FeaturesContext.Provider&gt;,
    );

    expect(screen.queryByText(&quot;Settings&quot;)).toBeNull();
  });

  it(&quot;shows Settings if the feature is enabled&quot;, async () =&gt; {
    render(
      &lt;FeaturesContext.Provider value={{ newSettingsPage: () =&gt; true }}&gt;
        &lt;Menu /&gt;
      &lt;/FeaturesContext.Provider&gt;,
    );

    expect(screen.queryByText(&quot;Settings&quot;)).not.toBeNull();
  });
});
</code></pre>
<h2><code>&lt;FeatureFlag /&gt;</code>, un componente para abstraernos por completo</h2>
<p>Si utilizamos la API de contextos, podemos ir todavía un paso más allá y
abstraernos por completo de la gestión de funcionalidades disponibles. En este
caso, vamos a crear un componente <code>FeatureFlag</code> que recibirá la flag sobre la
que queremos trabajar y los nodos que queremos ocultar en caso de no estar
disponible:</p>
<pre><code class="language-tsx">import { ReactNode } from &quot;react&quot;;
import { Features, useFeatures } from &quot;../lib/Features&quot;;

type FeatureFlagProps = { children: ReactNode; flag: keyof typeof Features };

export function FeatureFlag({ children, flag }: FeatureFlagProps) {
  const features = useFeatures();

  if (features[flag]()) {
    return &lt;&gt;{children}&lt;/&gt;;
  }

  return null;
}
</code></pre>
<p>Al definir la prop de <code>flag</code> como <code>keyof typeof Features</code> estamos tomando
ventaja de la ayuda del compilador de TypeScript, que nos dirá automáticamente
que funcionalidades existen y evitará que utilicemos flags que no se encuentran
en el objeto global de <code>Features</code>.</p>
<pre><code class="language-tsx">import { FeatureFlag } from &quot;./FeatureFlag&quot;;

export function Menu() {
  return (
    &lt;nav&gt;
      &lt;ul&gt;
        &lt;li&gt;
          &lt;a href=&quot;/dashboard&quot;&gt;Dashboard&lt;/a&gt;
        &lt;/li&gt;

        &lt;li&gt;
          &lt;a href=&quot;/profile&quot;&gt;Profile&lt;/a&gt;
        &lt;/li&gt;

        &lt;FeatureFlag flag=&quot;newSettingsPage&quot;&gt;
          &lt;li&gt;
            &lt;a href=&quot;/settings&quot;&gt;Settings&lt;/a&gt;
          &lt;/li&gt;
        &lt;/FeatureFlag&gt;
      &lt;/ul&gt;
    &lt;/nav&gt;
  );
}
</code></pre>
<p>Con este último enfoque, nuestras pruebas anteriores utilizando el proveedor del
contexto de feature flags seguirán funcionando (ya que es el mecanismo sobre el
que se construye todo) a la vez que tomamos ventaja de un diseño mucho más
idiomático, encapsulando la gestión de feature flags en su propio componente
React.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Liderazgo técnico y generación de espacios]]></title>
        <id>https://codecoolture.com/notes/liderazgo-tecnico-generacion-espacios</id>
        <link href="https://codecoolture.com/notes/liderazgo-tecnico-generacion-espacios"/>
        <updated>2020-11-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Reflexionando sobre mi trabajo los últimos años, me doy cuenta de que lo más valioso que he conseguido ha sido facilitar espacios de reflexión, discusión y aprendizaje continuo.]]></summary>
        <content type="html"><![CDATA[<h1>Liderazgo técnico y generación de espacios</h1>
<p>Reflexionando sobre mi trabajo los últimos años, donde he tenido que cumplir con
ese rol dual de liderazgo técnico (tech lead, lead engineer) y manager de
equipos (engineering manager, vp of engineering) en startups con equipos de
producto e ingeniería pequeños (máximo 10-12 personas), me doy cuenta de que
<strong>lo más valioso que he conseguido ha sido facilitar espacios de reflexión,
discusión y aprendizaje continuo</strong>.</p>
<p>¿A qué me refiero cuando hablo de espacios? Realmente, a nada físico o temporal,
sino a una manera de entender el trabajo del equipo y sus actividades en el día
a día. En muchas ocasiones, especialmente en los contextos en los que yo me he
desarrollado, nos vemos atrapados en un ritmo frenético de trabajo (con el
objetivo de demostrar la viabilidad de la empresa, buscar su product market fit,
conseguir una nuevo cliente, etc.) y ese rodillo puede sepultar las capacidades
del equipo para abstraerse y ganar la perspectiva necesaria para servir como
motor de cambio y mejora continua. Aunque seguro que no únicamente en startups
se vive con prisa, ¿verdad? 🙂</p>
<p>Mis iniciativas en este ámbito han orbitado siempre en torno a los siguientes 3
puntos:</p>
<ul>
<li><strong>Utilizar cada tarea (story, feature) como una oportunidad única para
aprender</strong>: como desarrollador, no hay curso o taller que me haya enseñado más
que el propio día a día escribiendo código y desafiando mi propia manera de
hacer las cosas una y otra vez en búsqueda de soluciones alternativas que sean
mejores (más sostenibles, escalables). Introducir en el equipo el mindset de
que cada nueva tarea es una oportunidad para aprender y experimentar requiere
tiempo, y constancia (y, especialmente, ¡no desdecirte a las primeras de
cambio!), pero estás contribuyendo a crear un espacio de aprendizaje continuo
en el día a día.</li>
<li><strong>Utilizar cada code review como un espacio de discusión</strong>: este espacio viene
casi <em>de gratis</em>, ya que no son pocos los equipos que tienen integrado en su
día a día la revisión de código a través de pull/merge requests. Me gusta
fomentar un entorno donde las revisiones de código no sean únicamente un
trabajo de revisión (valga la redundancia) sino que se utilicen como un
instrumento de aprendizaje y conversación. Evidentemente, con matices, ya que
no todas las merge requests contienen cambios tan interesantes como para
generar un debate a su alrededor. Del mismo modo, no todos los debates merecen
bloquear una merge request, por lo que debería ser natural continuar una
discusión incluso habiendo fusionado ya los cambios propuestos (¡o incluso
arrancar la discusión con la merge request ya cerrada!).</li>
<li><strong>Crear eventos recurrentes PARA el equipo</strong>: y aquí hablo únicamente de mi
experiencia trabajando en empresas de producto. Hay pocas cosas que generen
más inercia que un compromiso explícito por parte de la empresa en desarrollar
una cultura de aprendizaje continuo. Sin necesidad de negociar cosas (tan
importantes) como presupuestos de formación, es posible realizar pequeñas
inversiones a través de actividades como clubs de lectura (una hora a la
semana -¡en <a href="https://privacycloud.com/">PrivacyCloud</a> lleva funcionando desde
2017!), meetups internos donde integrantes del equipo puedan compartir hitos,
realizar presentaciones sobre aprendizajes de las últimas semanas, ver alguna
charla juntas, practicar una kata...</li>
</ul>
<h2>Y de manera tangencial...</h2>
<ul>
<li>En mi experiencia, invertir tiempo en <strong>tener ciclos de feedback (muy) cortos
fomenta sin lugar a dudas espacios de experimentación dentro del equipo</strong>. A
todos los niveles. Si poner cambios en producción se puede hacer de manera
autónoma, rápida y confiable, me animaré seguro a validar diferentes hipótesis
lo antes posible. Si se cuenta con rituales como retrospectivas (en un
contexto donde se puedan realizar de manera honesta) cada 1-2 semanas,
abrazaré el cambio con mayor seguridad, ya que podré ir revisándolo cada poco.</li>
<li>Las pull requests son un compromiso en el camino por alcanzar un trabajo 100%
colaborativo (a través de pair o mob programming -dinámicas que aún no he
conseguido interiorizar completamente ni ver aplicadas de manera recurrente en
ningún equipo en los que he trabajado, pero que me encantaría). Razón de más
para aprovechar esos tiempos de revisión para crear nuevos espacios de
discusión.</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Test-driven front-end development]]></title>
        <id>https://codecoolture.com/blog/test-driven-front-end-development</id>
        <link href="https://codecoolture.com/blog/test-driven-front-end-development"/>
        <updated>2020-11-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[El desarrollo de cualquier aplicación web es complejo. Hay un montón de funcionalidad por crear y, seguramente, poco tiempo 🤯 Sin embargo, con la nueva generación de herramientas front-end hay una metodología que nos puede ayudar a no perder el foco y entregar valor de manera continua, con confianza.]]></summary>
        <content type="html"><![CDATA[<h1>Test-driven front-end development</h1>
<blockquote>
<p>Este artículo fue publicado originalmente en la edición de 2020 de
<a href="https://octuweb.com/test-driven-front-end-development/">Octuweb</a>.</p>
</blockquote>
<p>En la edición de 2018 <strong>Cristina Ponce</strong> publicó
<a href="https://octuweb.com/testing-front/">Testing en el front</a>, una guía sobre los
diferentes tipos de pruebas que podemos realizar en aplicaciones front-end.
Apoyándonos en ese artículo, vamos a hablar aquí de cómo aprovechar la nueva
generación de herramientas para alcanzar flujos de desarrollo que, hasta hace
solo unos años, no eran (tan) fácilmente aplicables en este contexto:
<strong>Test-Driven Development</strong> (o <strong>TDD</strong>).</p>
<h2>Pero primero, ¿qué es TDD?</h2>
<p>Test-Driven Development es una metodología que se basa en aplicar pequeños
ciclos de desarrollo con el objetivo de resolver casos de prueba. De manera más
concreta, lo podemos definir en 3 pasos:</p>
<ol>
<li>Codificar una prueba que defina el nuevo comportamiento que queremos añadir a
nuestro sistema</li>
<li>Escribir la menor cantidad de código posible que nos permita hacer pasar el
test anterior</li>
<li>Mejorar el código anterior utilizando las pruebas como red de seguridad
(a.k.a <em>refactoring</em>)</li>
</ol>
<p>En TDD clásico, lo habitual es comenzar por las entidades más internas de
nuestro sistema para ir construyendo capas una encima de otra hasta terminar de
implementar la funcionalidad. En front-end sin embargo, y con las herramientas
actuales, lo más natural es utilizar una variación denominada <strong>ATDD</strong>
(inspirada en <strong>Outside-in</strong>, un enfoque de TDD que se originó en la comunidad
de eXtreme Programming de Londres), donde se empieza creando un primer test en
la capa más externa del sistema (en este caso, la interfaz o un componente) para
ir construyendo desde ahí el resto de la funcionalidad.</p>
<h2>Escribiendo nuestro primer test</h2>
<p>En su sentido más estricto, TDD es una herramienta de desarrollo (un flujo de
trabajo, una metodología) y no tiene que verse como un instrumento de calidad
(entendiendo esta como la disciplina para el control de defectos). Por tanto, su
objetivo es ayudar a las programadoras a entregar valor lo antes posible, con
confianza. En ATDD, por ejemplo, el primer test nos tiene que permitir poner el
foco en el problema que vamos a resolver y servirnos como guía durante el
desarrollo de la funcionalidad. Lo habitual es intentar reflejar en este primer
test los criterios de aceptación que perseguimos cumplir con la historia de
usuario en curso.</p>
<p>Por ejemplo, supongamos que estamos trabajando en el front-end para la web de
una editorial de libros y queremos añadir una página de contacto:</p>
<blockquote>
<p>Es posible acceder a una página de contacto para, indicando email, asunto y
mensaje, ponerse en contacto con la editorial. Una vez completada la
operación, se realizará una redirección a una página de éxito con un mensaje
que indique que todo ha ido bien.</p>
<p>Hay disponible un endpoint <code>/api/contact</code> que completa la operación en el
back-end.</p>
</blockquote>
<p>Utilizando <a href="https://www.cypress.io/"><strong>Cypress</strong></a>, podemos trasladar esta
descripción a una prueba de alto nivel como la siguiente:</p>
<pre><code class="language-typescript">// Location: cypress/integration/sendContactMessage.test.ts

context(&quot;sendContactMessage&quot;, () =&gt; {
  specify(&quot;A user can send a contact message&quot;, () =&gt; {
    // Setup
    cy.server();
    cy.route2(&quot;/api/contact&quot;, { statusCode: 200 });

    // Act
    cy.visit(&quot;/contact&quot;);
    cy.findByLabelText(/tu email/i).type(&quot;hola@codecoolture.com&quot;);
    cy.findByLabelText(/asunto/i).type(&quot;Información sobre próximos libros&quot;);
    cy.findByLabelText(/mensaje/i).type(
      &quot;Hola, me gustaría obtener más información sobre próximos libros.&quot;,
    );
    cy.findByText(/enviar/i).click();

    // Assert
    cy.url().should(&quot;eql&quot;, Cypress.config().baseUrl + &quot;/contact/success&quot;);
    cy.findByText(/tu mensaje ha sido enviado con éxito/i).should(&quot;exist&quot;);
  });
});
</code></pre>
<p>La prueba anterior codifica el escenario de aceptación básico: primero, hacemos
que Cypress simule la respuesta al endpoint <code>/api/contact</code> para indicar que todo
ha ido bien (devolverá un código <code>200</code>), y después interactuamos con la
aplicación para ir a la página de contacto y completar el formulario. Por
último, validamos que se ha llevado al usuario a la página de éxito tras enviar
el formulario.</p>
<blockquote>
<p>Ahora que hemos visto un ejemplo, seguramente nos sea más sencillo explicar
qué es Cypress: un framework de testing para construir pruebas de aceptación
sobre un navegador, utilizando JavaScript.</p>
</blockquote>
<p>En el ejemplo anterior, la prueba se ejecutará sobre nuestra propia aplicación.
En este caso, <strong>como todavía no hemos escrito código de producción, lo que
esperamos es que el test falle</strong>. Es ahora cuando tenemos que escribir la mínima
cantidad posible de código para que este test pueda pasar.</p>
<pre><code class="language-typescript">// Location: pages/contact.tsx

export default function Contact() {
  return (
    &lt;main&gt;
      &lt;Formik
        initialValues={{ email: &quot;&quot;, subject: &quot;&quot;, message: &quot;&quot; }}
        onSubmit={async ({ email, subject, message }) =&gt; {
          const response = await fetch(&quot;/api/contact&quot;, {
            body: JSON.stringify({ email, subject, message }),
            headers: { &quot;content-type&quot;: &quot;application/json&quot; },
            method: &quot;post&quot;,
          });

          if (response.ok) {
            window.location.href = &quot;/contact/success&quot;;
          }
        }}
      &gt;
        {() =&gt; {
          return (
            &lt;Form&gt;
              &lt;label&gt;
                Tu email &lt;Field id=&quot;email&quot; name=&quot;email&quot; /&gt;
              &lt;/label&gt;

              &lt;label&gt;
                Asunto &lt;Field name=&quot;subject&quot; /&gt;
              &lt;/label&gt;

              &lt;label&gt;
                Mensaje &lt;Field name=&quot;message&quot; /&gt;
              &lt;/label&gt;

              &lt;button type=&quot;submit&quot;&gt;Enviar&lt;/button&gt;
            &lt;/Form&gt;
          );
        }}
      &lt;/Formik&gt;
    &lt;/main&gt;
  );
}
</code></pre>
<pre><code class="language-typescript">// Location: pages/contact/success.tsx

export default function ContactSuccess() {
  return &lt;p&gt;¡Enhorabuena! Tu mensaje ha sido enviado con éxito&lt;/p&gt;;
}
</code></pre>
<p>Obviando algunos detalles de implementación (como el uso de
<a href="https://formik.org/">Formik</a> para el formulario), los dos fragmentos de código
anteriores muestran una posible implementación (básica pero funcional) que sirve
para hacer pasar nuestro primer test de aceptación. En este punto, podemos
añadir CSS a nuestra nueva página o extraer comportamientos a otro tipo de
entidades (por ejemplo, mover la operación de <code>onSubmit</code> a un servicio). Si
nuestro test sigue en verde al completar los cambios, tendremos la certeza de
que no hemos roto nada ✅</p>
<h2>Aplicando ciclos de desarrollo más pequeños</h2>
<p>Aunque Cypress es un magnífico framework de testing, las pruebas de tan alto
nivel suelen venir con algunos compromisos: es difícil poder ejercitar todos los
caminos de ejecución posibles y son lentas. Recordad que con TDD estamos
buscando mejorar nuestra productividad por lo que <strong>necesitamos que los ciclos
de feedback sean lo más cortos posibles</strong>. Para ello, mi consejo es utilizar
pruebas de aceptación para cubrir el <em>happy path</em> de la funcionalidad (y quizás
algún escenario de error clave) y después iterar en ciclos de desarrollo más
pequeños facilitados por pruebas de una granularidad más baja (en front-end,
podríamos entenderlas como híbridos de integración + unitaria, centradas en
componentes).</p>
<p>Si volvemos al ejemplo anterior, seguramente hay ciertas reglas de experiencia
de usuario que queramos validar sobre el formulario de contacto: que no se pueda
completar la operación sin un email de remite o sin el cuerpo del mensaje, que
aparezcan correctamente los mensajes de error, que los campos permitan
únicamente ciertos patrones, etc. Aunque estas pruebas se podrían hacer también
utilizando Cypress, su latencia es a menudo lo suficientemente grande como para
preferir moverlos a tests de más bajo nivel (por lo general, más rápidos).</p>
<p>Para hacer pruebas de componentes (en React, aunque las mismas herramientas
están disponibles en otros frameworks como Vue o Angular) mi consejo es utilizar
<a href="https://testing-library.com/"><strong>Testing Library</strong></a> en conjunción con
<a href="https://jestjs.io/"><strong>Jest</strong></a>. Por ejemplo, vamos a añadir un nuevo
comportamiento a nuestra página de Contacto, aunque esta vez iterando en un
nivel de abstracción más bajo:</p>
<blockquote>
<p>El formulario sólo debe enviarse si contiene un email de remite y un mensaje.</p>
</blockquote>
<pre><code class="language-tsx">// Location: components/ContactForm.test.tsx

describe(&quot;ContactForm&quot;, () =&gt; {
  it(&quot;does not submit the form if some required fields are missing&quot;, async () =&gt; {
    // Setup
    const spy = jest.fn();
    render(&lt;ContactForm onSubmit={spy} /&gt;);

    // Act
    await user.type(
      screen.getByLabelText(/asunto/i),
      &quot;Información próximos libros&quot;,
    );

    user.click(screen.getByText(/enviar/i));

    // Assert
    await expect(
      screen.findAllByText(&quot;Este campo es obligatorio.&quot;),
    ).resolves.toHaveLength(2);

    await waitFor(() =&gt; expect(spy).not.toHaveBeenCalled());
  });
});
</code></pre>
<p>El test anterior codifica el nuevo comportamiento que queremos validar. Veréis
que, en un primer vistazo, la apariencia del test es similar al primero que
creamos utilizando Cypress. La única diferencia es que aquí se prueba el
componente de manera aislada en lugar de simular a un usuario real utilizando la
aplicación. En Testing Library, no hay ningún navegador ejecutándose en
paralelo, como sí ocurre con Cypress; así, mientras el último que hemos escrito
podemos ejecutarlo en ~2 segundos, el primero necesita de ~22 segundos.</p>
<p>Cuando trabajamos a un nivel de granularidad más bajo, nuestros tests pueden
afectar al diseño de nuestros componentes (por lo general, haciéndolos más
sencillos de probar). En este caso, he decidido inyectar la función que gestiona
el envío del formulario para poder reemplazarla por un espía que me permita
validar que no se ha invocado cuando no debía (aunque también podríamos haber
espiado el módulo HTTP con <a href="https://github.com/nock/nock"><strong>nock</strong></a>). Este es
otro de los beneficios clave de TDD, ser capaces de ir definiendo el diseño de
nuestras interfaces a medida que escribimos las pruebas.</p>
<p>Como todos estos cambios no están repercutiendo en cambios de comportamiento a
nivel de aceptación, nuestro test de Cypress debería seguir pasando después de
cada modificación, ayudándonos de nuevo a garantizar que no hemos roto nada ✅.</p>
<p>Ahora, al igual que en el ejercicio anterior, tendríamos que escribir la menor
cantidad de código que sirva para hacer pasar este test.</p>
<blockquote>
<p>Pss! Podéis ver el ejemplo completo en
<a href="https://github.com/codecoolture/octuweb-2020">este repositorio de GitHub</a> 👀</p>
</blockquote>
<h2>Conclusión</h2>
<p>¿Que conseguiremos aplicando un flujo similar al anterior? En la literatura de
TDD, estaríamos aplicando lo que se conoce como
<a href="http://coding-is-like-cooking.info/2013/04/outside-in-development-with-double-loop-tdd/">Outside-In development with Double Loop TDD</a>
o el proceso descrito en el libro
<a href="https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests">Growing Object-Oriented Software, Guided by Tests</a>.</p>
<p>Primero, arrancamos con un test de aceptación (o del nivel de granularidad más
alto que podamos) que nos ayudará a mantener el foco en la funcionalidad que
queremos resolver. En ocasiones, este test puede estar fallando durante varias
horas porque necesite de otros ciclos complementarios más pequeños que nos
ayuden avanzar (el ejemplo anterior era tan sencillo que no lo hemos
necesitado). Para esos ciclos complementarios es donde podemos hacer uso de
flujos como TDD clásico (útil para avanzar en piezas de bajo nivel como
funciones, clases, servicios) y herramientas como Testing Library (para probar
los diversos componentes que construyan la interfaz) o <em>simplemente</em> Jest (para
lógica de negocio como controladores, funciones de utilidad, etc.).</p>
<h2>Otras referencias</h2>
<ul>
<li>Además de los enlaces contenidos en el artículo, podéis encontrar más
referencias a TDD en
<a href="https://www.notion.so/codecoolture/Public-References-50b1e927fe1641748f95610353e97b7f">esta página</a>.</li>
<li>Cypress tiene una sección de
<a href="https://docs.cypress.io/guides/references/best-practices.html">mejores prácticas</a>
con algunos consejos muy útiles sobre cómo escribir pruebas de aceptación.</li>
<li><a href="https://twitter.com/kentcdodds/">Kent C. Dodds</a> (creador de Testing Library)
tiene bastantes artículos relacionados con testing de aplicaciones front-end
(desde TDD hasta diferentes estrategias de testing). Podéis encontrarlos en
<a href="https://kentcdodds.com/blog?q=testing">su blog</a>.</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #5: Q3 2020]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q3-2020</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q3-2020"/>
        <updated>2020-10-13T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<h1>Quarterlinks #5: Q3 2020</h1>
<p>Vamos con la colección de recursos interesantes leídos durante julio, agosto y
septiembre de este 2020.</p>
<h2>💻 Blogposts</h2>
<ul>
<li><strong><a href="http://antirez.com/news/124">Writing system software: code comments</a></strong>: al igual que me pasó
con
<a href="/notes/a-philosophy-of-software-design"><em>A Philosophy of Software Design</em></a>,
disfruto un montón con los textos que hablan sobre cómo escribir buenos
comentarios (reflexionando, creo que viene de haber sufrido en equipos donde
se malinterpretaban algunos principios de <em>Clean Code</em> y el código
autodocumentado). En este caso, el artículo va un poco más allá y realiza una
clasificación con los diferentes tipos de comentarios que nos podemos
encontrar, a la vez que muestra ejemplos concretos sobre el código fuente de
Redis. Tengo sentimientos encontrados con lo que el autor denomina <em>Guide
comments</em> pero me encantaría conocer vuestra opinión!</li>
<li><strong><a href="https://www.mrlacey.com/2020/07/youve-only-added-two-lines-why-did-that.html">You’ve only added two lines - why did that take two days!</a></strong>:
creo que este artículo recoge muy bien el heurístico que la mayoría utilizamos
al resolver bugs y que no siempre se consigue entender por personas que están
fuera del proceso de escritura de software (empezando por ese <em>all lines of
code are NOT equal</em>).</li>
<li><strong><a href="https://iism.org/article/why-are-ceos-failing-software-engineers-56">Why are CEOs failing software engineers?</a></strong>: lectura interesante para
personas que se encuentren en áreas de gestión/liderazgo técnico en
organizaciones de software (¿queda alguna que no lo sea? 😉).</li>
<li><strong><a href="https://martinfowler.com/articles/dont-compare-averages.html">Don’t Compare Averages</a></strong>: aquí, Martin Fowler sale un poco de su
temática habitual sobre ingeniería de software para hablar de diferentes
visualizaciones que nos ayuden a comunicar información de manera más efectiva
(es decir, escapando de las habituales gráficas de barras mostrando medias
aritméticas).</li>
<li><strong><a href="https://medium.com/cabify-product/the-cabify-engineering-stack-2020-edition-34edcaff5ad0">The Cabify engineering stack, 2020 edition</a></strong>: mola mucho conocer
las tripas tecnológicas de grandes organizaciones de software y, en este caso,
Cabify nos enseña parte de su stack y cómo gestionar una arquitectura web de
alta disponibilidad y mucho, mucho <em>tráfico</em> 🙂.</li>
</ul>
<h2>🎥 Vídeos</h2>
<ul>
<li><strong><a href="https://youtu.be/BFFY9Zor6zw">Tidy First?</a></strong>: un vídeo muy cortito donde Kent Beck introduce el
concepto de dividir en diferentes pull requests los cambios de comportamiento
y los cambios de estructura. Sin llegar a la clarividencia de Beck, creo que
esta nota sobre
<a href="/notes/effective-code-reviews">revisiones de código efectivas</a> y cómo aplicar
ahí el principio de responsabilidad única puede ayudar a empezar a andar ese
mismo camino.</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #4: Q2 2020]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q2-2020</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q2-2020"/>
        <updated>2020-07-20T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<h1>Quarterlinks #4: Q2 2020</h1>
<p>Con unos días de retraso pero ahí va el conjunto de links con contenido
interesante consumido durante el segundo trimestre de 2020.</p>
<p>Como curiosidad, ha sido un trimestre movidito (¡COVID aparte!) y he vuelto a
unirme al equipo de <a href="https://privacycloud.com">PrivacyCloud</a> para tratar de
ayudar al equipo a alcanzar nuevos objetivos.</p>
<h2>💻 Blogposts</h2>
<ul>
<li><strong><a href="http://labs.spotify.com/2020/04/14/when-should-i-write-an-architecture-decision-record/">When should I write an Architecture Decision Record?</a></strong>: Cómo y cuándo
se escriben ADRs en Spotify. Este artículo ha servido de empuje para que
empecemos a utilizar este tipo de documentación dentro del equipo.</li>
<li><strong><a href="https://svpg.com/empowered-engineers-faq/">Empowered Engineers FAQ</a></strong>: En general, todos los
artículos del Silicon Valley Product Group sobre cómo construir equipos de
producto son muy recomendables pero este, que es uno de sus últimos artículos
al respecto, responde a varias preguntas enviadas por personas con dudas sobre
cómo implementar esta manera de trabajar en sus equipos.</li>
<li><strong><a href="https://www.javierescribano.me/ana-asuero-aplazame/">Ana Asuero, Aplazame CPO, on how to do product when there are limitations
you can’t control</a></strong>: Pues poco más que añadir; <em>insights</em> muy
interesantes que nos llegan desde Aplazame sobre desarrollo de producto.</li>
<li><strong><a href="https://3perf.com/blog/notion/">Case study: Analyzing Notion app performance</a></strong>: Artículo
mastodóntico sobre cómo se podría mejorar el rendimiento de la aplicación web
de Notion. Más allá del caso de estudio concreto, para mí el valor del
artículo se centra en conocer qué estrategias existen para mejorar el
rendimiento de aplicaciones web (al final, todas sufren de más o menos los
mismos problemas, aunque a diferente escala).</li>
</ul>
<h2>🎥 Webinars</h2>
<ul>
<li><strong><a href="https://www.youtube.com/watch?v=xeGHvXwCk1M">Technology at the Core of Product Discovery</a></strong>: En este
webinar, <a href="https://twitter.com/eferro">Eduardo Ferro</a> presenta la importancia de la tecnología
subyacente como <em>enabler</em> para implementar una cultura de <em>product discovery</em>
en equipos de producto.</li>
</ul>
<h2>📚 Libros</h2>
<ul>
<li><strong><a href="https://www.goodreads.com/book/show/18077903-creativity-inc">Creativity, Inc.</a></strong>: Ed Catmull (director en Pixar Animation y
Disney Animation) nos sumerge en un viaje por la historia de Pixar y por su
propia estructura organizativa (que les ha servido para revolucionar la
industria de la animación desde la innovación tanto organizativa como
tecnológica). Aunque pueda no parecerlo en primera instancia, todos los
capítulos de este libro contienen píldoras muy interesantes para cualquier
equipo de desarrollo de producto y yo, sin duda, me veré influenciado por su
lectura de aquí en adelante.</li>
</ul>
<h2>🎱 Bola extra: DEVS</h2>
<p>Esta <a href="https://www.filmaffinity.com/es/film120510.html">serie de HBO</a> es un <em>thriller</em> de ciencia ficción donde, en una
empresa de alta tecnología, desaparece un ingeniero de software en
circunstancias sospechosas... su pareja (también ingeniera de software) comienza
una investigación para tratar de esclarecer los detalles alrededor del caso 🙂</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Portfolio y blog utilizando NEXT.js]]></title>
        <id>https://codecoolture.com/notes/portfolio-blog-nextjs</id>
        <link href="https://codecoolture.com/notes/portfolio-blog-nextjs"/>
        <updated>2020-07-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Detalles y curiosidades sobre cómo construí mi portfolio utilizando NEXT.js]]></summary>
        <content type="html"><![CDATA[<h1>Portfolio y blog utilizando NEXT.js</h1>
<p>En esta nota os quiero contar algún detalle sobre cómo construí este website
utilizando NEXT.js, un framework desarrollado por Vercel que utiliza React como
librería principal y que permite, de manera sencilla, servir una aplicación
React desde el servidor utilizando <em>server-side rendering</em> (¡aunque quedarnos
únicamente con esto sería simplificarlo demasiado!).</p>
<blockquote>
<p>Mi intención aquí no es hacer un recorrido en profundidad de NEXT.js o cómo
implementar un portfolio utilizándolo. Si os pica la curiosidad, el proyecto
tiene una muy buena <a href="https://nextjs.org/docs/getting-started">documentación</a>,
con
<a href="https://github.com/vercel/next.js/tree/canary/examples">multitud de ejemplos</a>
y <a href="https://nextjs.org/learn/basics/create-nextjs-app">tutoriales</a>.</p>
</blockquote>
<h2>Iterando entre diferentes versiones de Next</h2>
<p>El primer commit para desarrollar <a href="http://codecoolture.com">codecoolture.com</a> es
del 24 de agosto de 2018. Por aquel entonces las necesidades del proyecto eran
tener un montón de ficheros estáticos que explicasen qué servicios tenía pensado
ofrecer como <em>freelance</em> y, para ello, utilicé la funcionalidad de Next:
<code>next export</code>, que genera un conjunto de ficheros HTML como resultado de aplicar
<em>server-side rendering</em> a la aplicación y <em>exportar</em> su resultado.</p>
<p>Más adelante, me decidí por añadir un blog (y este apartado de notas) y en ese
punto, las cosas empezaron a complicarse (sobre porqué decidí implementar mi
blog <em>in house</em> en lugar de utilizar plataformas como Medium, las razones son
muy parecidas a las expuestas por Marina Aisa cuando
<a href="https://marinaaisa.com/es/blog/blog-usando-vue-nuxt-markdown/">escribió sobre su experiencia trabajando con Nuxt</a>).
Para seguir manteniendo ese enfoque estático, tenía que añadir las diferentes
entradas manualmente en alguna página tipo índice que sirviera para que el
proceso de exportación supiese que existían y pudiese crear sus ficheros HTML
relacionados (simplificándolo mucho, sería algo similar a lo que necesita un bot
para hacer <em>crawling</em> de una web).</p>
<p>Para no depender de un proceso manual, me decidí por abandonar la exportación
estática y desplegar Next en una instancia de AppEngine para hacer que las
páginas del blog (junto con su índice) se comenzasen a pintar dinámicamente
utilizando SSR. Veréis que aunque Vercel es una plataforma que le encaje como
anillo al dedo a un proyecto que utilice Next, este se puede desplegar en
cualquier servicio que admita ejecutar aplicaciones Node (aunque no todos son
capaces de sacarle partido al potencial <em>serverless</em> del framework, pero eso
sería un tema para otro momento).</p>
<p>Actualmente, y tras actualizar Next a su versión 9.3, pude recuperar la
exportación estática gracias a la adición de una función <code>getStaticPaths</code> que
permite indicarle a Next (de manera programática, en tiempo de compilación) qué
paginas existen y cuáles tiene que exportar. En el mismo fichero que se utiliza
para definir una entrada en el blog, se exporta un función cómo la siguiente:</p>
<pre><code class="language-tsx">export const getStaticPaths: GetStaticPaths = async () =&gt; {
  const repository = await MarkdownRepository.fromDirectory(
    getConfig().writing.articles,
  );

  const paths = (await repository.all()).map((article) =&gt; {
    const slug = article.metadata.slug;

    if (!slug) {
      throw new Error(
        `ERROR: Missing slug for article: ${JSON.stringify(article.metadata)}`,
      );
    }

    return { params: { slug } };
  });

  return { fallback: false, paths };
};
</code></pre>
<p>La función pide a un repositorio de artículos que devuelva todos los documentos
que existen y utiliza esta información para indicar a Next cómo encontrarlos (a
través de la propiedad <code>slug</code> de cada <em>path</em>). <code>MardownRepository</code> es una
entidad de mi proyecto (y no algo que venga con Next), y es que el patrón
<em>Repository</em> es una abstracción que utilizo muy habitualmente ya que encaja en
un montón de escenarios (realmente, en casi cualquiera que tenga acceso a
datos).</p>
<blockquote>
<p>Como <a href="https://twitter.com/cassidoo">Cassidy Williams</a> lo explica mejor que yo,
podéis echar un vistazo a
<a href="https://www.netlify.com/blog/2020/05/04/building-a-markdown-blog-with-next-9.4-and-netlify/">este blogpost</a>
donde explica en profundidad cómo crear un blog con Next.</p>
</blockquote>
<h2>MDX: escribiendo contenido de manera cómoda</h2>
<p>No, la verdad que React + JSX no es la mejor manera para escribir contenido de
manera ágil y cómoda... Para hacerlo, me decidí por un
<a href="https://github.com/vercel/next.js/tree/canary/packages/next-mdx">plugin de Next</a>
que permite generar páginas escribiendo directamente ficheros
<a href="https://mdxjs.com/">MDX</a> (que, en resumen, son ficheros en formato Markdown
pero que permiten integrar componentes React directamente en el cuerpo del
documento). Este mismo esquema es el que utilicé para escribir los artículos del
blog y las notas; todo junto, en resumen, hace que el 100% del contenido de la
web se escriba en MDX y únicamente utilice React + JSX para definir los
componentes.</p>
<p>Además, con MDX, podemos indicar qué componentes React queremos mapear con cada
elemento HTML. Esto es especialmente útil para poder reutilizar los mismos
componentes a través de toda la aplicación:</p>
<pre><code class="language-tsx">import { Blockquote } from &quot;../../components/Blockquote&quot;;
import { Link } from &quot;../../components/Link&quot;;
import { List } from &quot;../../components/List&quot;;
import { Text } from &quot;../../components/Text&quot;;
import { Title } from &quot;../../components/Title&quot;;

/* ... */

&lt;MDX
  components={{
    a: Link,
    blockquote: Blockquote,
    h1: Title,
    ul: List,
  }}
&gt;
  {post.content}
&lt;/MDX&gt;;
</code></pre>
<h2>Otros detalles</h2>
<ul>
<li>Para los estilos de la aplicación me decanté por utilizar CSS y no una
solución CSS-in-JS, aunque seguramente mi decisión ahora hubiese sido distinta
(después de utilizar <code>emotion</code> durante los últimos meses, la verdad es que me
he sentido muy cómodo). Ambos enfoques se pueden utilizar sin mayores
problemas en Next (siendo el uso de CSS soportado por defecto, sin necesidad
de configurar nada).</li>
<li>La web se sirve desde Firebase Hosting (tengo la mayoría de proyectos en
Google Cloud y me era más cómodo mantener todo dentro de la misma nube que
desplegar este site en Vercel o Netlify -opciones también muy válidas y con
una <em>developer experience</em> muy bien ejecutada). Los despliegues están
automatizados a través de GitLab CI/CD.</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #3: Q1 2020]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q1-2020</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q1-2020"/>
        <updated>2020-04-03T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<h1>Quarterlinks #3: Q1 2020</h1>
<h2>💻 Blogposts</h2>
<ul>
<li><a href="https://medium.com/@FirstMark/githubs-cto-on-architecting-engineering-teams-that-scale-cb79dd6132ae"><strong>How GitHub’s CTO Architects Engineering Teams That Scale</strong></a></li>
<li><a href="https://paulosman.me/2019/12/30/production-oriented-development.html"><strong>Production Oriented Development</strong></a>: Si
solo tenéis tiempo para atender una recomendación, que sea esta 😁</li>
</ul>
<blockquote>
<p>[...] code in production is the only code that matters. Staging doesn’t
matter, code on your laptop doesn’t matter, QA doesn’t matter, only production
matters. Everything else is debt.</p>
</blockquote>
<ul>
<li><a href="http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions"><strong>Documenting Architecture Decisions</strong></a>:
Este blogpost tiene ya algunos años (2011) pero su idea es perfectamente
relevante. Documentar decisiones de arquitectura es la única manera de
empoderar a las personas que se vayan a hacer cargo del proyecto <em>en el
futuro</em>.</li>
</ul>
<blockquote>
<p>Agile methods are not opposed to documentation, only to valueless
documentation. Documents that assist the team itself can have value, but only
if they are kept up to date. Large documents are never kept up to date. Small,
modular documents have at least a chance at being updated</p>
</blockquote>
<h2>🛠 Código</h2>
<ul>
<li><a href="https://github.com/zalando/tech-radar"><strong>zalando/tech-radar</strong></a>: Herramienta
basada en el Tech Radar de ThoughtWorks y pensada para que equipos de
ingeniería puedan documentar el estado de su stack tecnológico.</li>
</ul>
<h2>📚 Libros</h2>
<ul>
<li><strong>Object-Oriented Reengineering Patterns</strong>: Publiqué una pequeña nota sobre el
libro <a href="/notes/object-oriented-reengineering-patterns">aquí</a>.</li>
</ul>
<h2>🎱 Bola extra: musicforprogramming</h2>
<p>Seguramente sea ya todo un clásico, pero
<a href="http://musicforprogramming.net/"><strong>musicforprogramming</strong></a> contiene un montón de
listas de reproducción para concentrarse programando (o haciendo cualquier otra
actividad que requiera foco 😄).</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[📚 Object-Oriented Reengineering Patterns]]></title>
        <id>https://codecoolture.com/notes/object-oriented-reengineering-patterns</id>
        <link href="https://codecoolture.com/notes/object-oriented-reengineering-patterns"/>
        <updated>2020-03-30T00:00:00.000Z</updated>
        <content type="html"><![CDATA[<h1>Object-Oriented Reengineering Patterns</h1>
<p><a href="https://www.amazon.es/Object-Oriented-Reengineering-Patterns-Engineering-Programming/dp/1558606394">Este libro</a>
es una magnífica colección de heurísticos y estrategias para ayudarnos a
comprender un sistema de software complejo y ser eficaces a la hora de poder
evolucionarlo y mantenerlo.</p>
<p>Los últimos capítulos están dedicados a estrategias de diseño de software que
permitan extender un modelo ya existente, y son los únicos donde se hace
referencia a orientación a objetos. Personalmente, también son los que menos
valor me han aportado, quizás porque ya han sido desarrollados ampliamente en
otro libros
(<a href="https://www.amazon.es/Practical-Object-Oriented-Design-Agile-Primer/dp/0134456475">Practical Object-Oriented Design</a>,
por poner un ejemplo).</p>
<p>Un libro muy interesante si te toca unirte a un proyecto ya en marcha o te
enfrentas a un cambio de trabajo, ya que independientemente del objetivo final
(reingeniería) sus consejos son muy útiles para poder entender bases de código
relativamente grandes, utilizando las herramientas y actores adecuados (que se
cubren en profundidad en la parte II: <em>Reverse Engineering</em>).</p>
<blockquote>
<p>A culture of continuous reengineering is a prerequisite for achieving ﬂexible
and maintainable object-oriented systems.</p>
</blockquote>
<ul>
<li>«<em>It is easy to get seduced by focussing on the technical problems that
interest you the most, rather than what is best for the project.</em>»</li>
<li>«<em>Other engineering disciplines rely on the laws of nature to hide irrelevant
details, but software engineering must build on less solid foundations.
Consequently, it is essential to pay attention to the details. The only
question is how to filter out those details that do not matter, because you
cannot possible investigate everything.</em>»</li>
<li>«<em>Documentation is almost always out of date with respect to the actual
situation. [...] Consequently, avoid to make important decisions based on
documentation only —first verify your findings by other means (in particular,
Read all the Code in One Hour and Interview During Demo)</em>»</li>
<li>«<em>As a rule of the thumb, assume that a single team can reengineer as much
code as they can write from scratch.</em>»</li>
<li>«<em>If you fail to deliver good initial results, you will learn a lot, but you
risk losing credibility. It is therefore critical to choose carefully initial
tasks which not only demonstrate value for the customer, but also have a high
chance of success. Therefore, take great care in estimating the effort of the
initial tasks.</em>»</li>
<li>«<em>Nevertheless, even outdated information may be useful, because at least it
tells you how the system was supposed to behave in the past. This is a good
starting point to infer how it is used today.</em>»</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Revisiones de código efectivas]]></title>
        <id>https://codecoolture.com/notes/effective-code-reviews</id>
        <link href="https://codecoolture.com/notes/effective-code-reviews"/>
        <updated>2020-03-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Un consejo sencillo para reducir la complejidad de las pull requests y facilitar su revisión]]></summary>
        <content type="html"><![CDATA[<h1>Revisiones de código efectivas</h1>
<p><a href="https://en.wikipedia.org/wiki/Single-responsibility_principle">Single-responsibility principle</a>
es, sin duda, uno de los principios de diseño de software que más me gusta.
Aplica muy bien a un montón de escenarios, tanto a escala &quot;micro&quot; (funciones,
clases) como &quot;macro&quot; (arquitectura, microservicios). Si estáis lidiando en un
escenario donde las <em>pull requests</em> son, habitualmente, más grandes de lo que os
gustaría y por tanto, necesitan de mucho tiempo para ser revisadas
(convirtiéndose casi accidentalmente en cuellos de botella) os ánimo a probar la
aplicación de SRP.</p>
<p>¿Cómo encajaría en este contexto? A mí me gusta enunciarlo de la siguiente
manera:</p>
<blockquote>
<p>Una pull request debe contener cambios relacionados con una única
responsabilidad.</p>
</blockquote>
<p>Como veis, dentro del enunciado anterior, tendrían cabida <em>code reviews</em> con
multitud de cambios pero (y este <em>pero</em> es importante) siempre y cuando estén
relacionados con una única responsabilidad. Y es que, en la práctica, la
complejidad a la hora de revisar una <em>pull request</em> no está tanto relacionada
con el número de cambios, sino con el volumen de responsabilidades que están
siendo cambiadas a la vez (es decir, un <em>renaming</em> por aquí junto a un cambio en
el código de esta función por allá).</p>
<p>Como ejemplo, uno de los sospechoso habituales de generar un montón de cambios:
renombrar un método, clase, etc. Si este cambio se traduce en una única <em>pull
request</em>, estaremos facilitando mucho la vida de la compañera que tenga que
revisar nuestro código ya que todos los cambios están relacionados con una única
<em>responsabilidad</em> y sólo deberá poner el foco en garantizar que la acción se
haya hecho correctamente (¡imaginad que, además, tuviera que validarlo junto a
otro montón de cambios de diversa índole que acompañen a la pull request!).</p>
<blockquote>
<p>La complejidad a la hora de revisar una <em>pull request</em> no está tanto
relacionada con el número de cambios, sino con el volumen de responsabilidades
que están siendo cambiadas a la vez.</p>
</blockquote>
<p>Conseguir un flujo así implica que tengamos que quitar de nuestra cabeza la idea
de que <em>1 feature</em> equivale a <em>1 pull request</em> y eso es algo que sólo podemos
conseguir si
<a href="/blog/decoupling-vcs-from-software-delivery">desacoplamos nuestro repositorio de nuestra estrategia de entrega de software</a>.</p>
<p>Por supuesto, todos los consejos habituales sobre cómo realizar buenas
revisiones de código aplican también con este enfoque (y si queréis un repaso
completo sobre cómo realizar <em>la pull request perfecta</em>, os recomiendo
<a href="https://www.youtube.com/watch?v=8-ymTkrZPLg">esta charla</a> de
<a href="https://twitter.com/patriciagao">Patricia Gao</a>).</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #2: Q4 2019]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q4-2019</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q4-2019"/>
        <updated>2020-01-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Ruby, Amazon, continuous delivery, engineering management...]]></summary>
        <content type="html"><![CDATA[<h1>Quarterlinks #2: Q4 2019</h1>
<h2>💻 Blogposts</h2>
<ul>
<li><a href="https://aws.amazon.com/builders-library/"><strong>The Amazon Builders’ Library</strong></a>:
Conjunto de artículos que reflejan como Amazon <em>builds and operates software</em>.
Se explican desde sistemas distribuidos a gestión de <em>pipelines</em> de
integración y entrega continua.</li>
<li><a href="https://metaredux.com/posts/2019/12/06/ruby-where-do-we-go-now.html"><strong>Ruby, Where do We Go Now?</strong></a>:
Es muy interesante ver la evoluación de Ruby para mantenerse como una
alternativa interesante todavía en 2020. Pero más interesante es leer cómo
Bozhidar Batsov (creador de <a href="https://github.com/rubocop-hq/rubocop">Rubocop</a>
-el linter más popular en el ecosistema Ruby) da su particular visión sobre el
estado actual del lenguaje en su versión 2.7, repasando algunas de sus
decisiones de diseño más controvertidas.</li>
<li><a href="https://medium.com/@flopezluis/el-role-de-un-engineering-manager-91afebbbf7d0"><strong>El role de un Engineering manager</strong></a>:
Este es el primero de una serie de artículos escritos por
<a href="https://twitter.com/flopezluis">Félix</a> para hablar de las responsabilidades
de un Engineering Manager y cómo utilizar varias de las herramientas de las
que disponemos: one on ones, performance reviews, etc. Un contenido súper
interesante y... ¡en español! 😉</li>
<li><a href="https://lorinhochstein.wordpress.com/2019/08/22/experts-arent-good-at-building-shared-understanding/"><strong>Experts aren’t good at building shared understanding</strong></a></li>
</ul>
<h2>📚 Libros</h2>
<p>Este último trimestre lo he dedicado a picotear artículos y capítulos de varios
libros pero, si tuviera que quedarme con uno, diría que
<a href="https://www.amazon.es/Accelerate-Software-Performing-Technology-Organizations/dp/1942788339/"><strong>Accelerate</strong></a>
es el mejor recurso para entender (y defender) porqué aplicar una cultura de
entrega continua es el camino a seguir para mejorar el rendimiento de un equipo
de desarrollo (y de cualquier empresa de software en general).</p>
<h2>🎱 Bola extra: Notion</h2>
<p>Durante este último trimestre he pasado a darle mucho uso a
<a href="https://www.notion.so/"><strong>Notion</strong></a> para administrar diferentes tareas,
proyectos y conocimiento. Es multiplataforma y su plan gratuito es lo bastante
amplio para poder utilizarlo (durante un tiempo largo) sin mucho problema.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Aplicando ATDD para resolver El Juego de la Vida]]></title>
        <id>https://codecoolture.com/blog/applying-atdd-to-game-of-life</id>
        <link href="https://codecoolture.com/blog/applying-atdd-to-game-of-life"/>
        <updated>2019-12-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[¿Qué es ATDD? Imagínate aplicar TDD no sólo para resolver pequeñas piezas de funcionalidad si no para conseguir un sistema desplegable en cada iteración.]]></summary>
        <content type="html"><![CDATA[<h1>Aplicando ATDD para resolver El Juego de la Vida</h1>
<blockquote>
<p>Nota: en la literatura, ATDD suele ir acompañado de un conjunto de prácticas y
herramientas más amplio que lo descrito en este artículo. Mi objetivo aquí es
transmitir mi experiencia sobre cómo aplicar parte de sus principios para
mejorar nuestra productividad a la hora de resolver determinados problemas,
visto únicamente desde el plano de desarrollo de software.</p>
</blockquote>
<p>Una de las situaciones más habituales que me he encontrado en los últimos años
cuando facilito coding dojos o coderetreats (donde muchas personas se enfrentan
por primera vez a resolver una <em>kata</em> aplicando metodologías como TDD) es
observar cómo los participantes empiezan atacando el problema de una manera que
no les ayuda a avanzar, sino más bien les obliga a perderse en pequeños detalles
de implementación o incluso a sufrir de cierta <em>parálisis por análisis</em>.</p>
<p>Al principio, yo también pensaba que aplicar TDD debería ser suficiente por sí
mismo para evitar esa fricción inicial y tener <em>working software</em> lo más rápido
posible, pero tras observarlo (y sufrirlo) durante varios años, me he dado
cuenta que no siempre es así. Cuando empezamos a trabajar con TDD es habitual
que tratemos de solucionar el problema desde aquellos puntos donde nos es más
sencillo poder aplicarlo (pequeñas piezas de bajo nivel, como una función
sencilla), aunque no sean las partes que nos ayuden a llegar antes a resolver el
problema (y por tanto, a entregar valor).</p>
<p>Como parte de la preparación para facilitar el
<a href="https://www.coderetreat.org/">GDCR19</a>, estuve trabajando en resolver el Juego
de la Vida utilizando un enfoque basado en
<a href="https://en.wikipedia.org/wiki/Acceptance_test%E2%80%93driven_development">ATDD</a>
(<em>acceptance test-driven development</em>), una aplicación de TDD que nos obliga a
pensar en pruebas de muy alto nivel (aceptación) con la idea de tener una
versión desplegable de nuestro sistema con cada iteración.</p>
<h2>El síndrome de la página en blanco, o <em>ese</em> primer test</h2>
<p>Una de las ventajas de aplicar ATDD es que esa primera <em>crisis</em> sobre cómo
atacar el problema me vino resuelta casi de base. En este caso, sabía que el
sistema debía ser un CLI que, a partir de un fichero de entrada, generase un
fichero de salida con la siguiente evolución del tablero
(<a href="http://codingdojo.org/kata/GameOfLife/#problem-description">aquí</a> tenéis un
enlace con las reglas del juego).</p>
<p>La primera porción de funcionalidad mínima (de alto nivel) que se me ocurrió
implementar fue un CLI que, dadas las condiciones anteriores, supiera
evolucionar un tablero con despoblación.</p>
<p>Seguramente, esta sea la diferencia más notable frente a tratar de resolver el
problema utilizando (únicamente) TDD a nivel unitario (de ahora en adelante,
UTDD -aunque no creo que este concepto esté definido en ningún sitio 😅). Con
UTDD nos vemos <em>obligados</em> a detectar desde el principio una primera entidad
sobre la que escribir los tests, lo que en muchas ocasiones me ha hecho perder
el foco y caer en la trampa del
<a href="https://wiki.c2.com/?BigDesignUpFront">Big Design Up Front</a>.</p>
<pre><code class="language-ts">const subject = join(__dirname, &quot;../src/cli.ts&quot;);

it(&quot;supports underpopulation&quot;, () =&gt; {
  const inputFilename = join(__dirname, &quot;./fixtures/underpopulation&quot;);
  const outputFilename = join(__dirname, &quot;./results/underpopulation&quot;);

  play(`${subject} --input=${inputFilename} --output=${outputFilename}`);

  const result = getResult(outputFilename);

  expect(result).toEqual([&quot;0 0 0&quot;, &quot;0 0 0&quot;, &quot;0 0 0&quot;].join(&quot;\n&quot;));
});
</code></pre>
<p>Pero vayamos paso a paso por el test anterior:</p>
<ul>
<li>La función <code>play</code> es un simple envoltorio que ejecuta en un shell la
instrucción indicada. En este caso, nuestro ejecutable es el fichero
<code>src/cli.ts</code> y se le pasan como parámetro ambos: el fichero de entrada con el
tablero inicial y el fichero de salida donde guardar la evolución.</li>
<li>Una vez ejecutado el script, recuperamos el resultado a partir del fichero de
salida indicado y comprobamos que sea el resultado esperado.</li>
</ul>
<p>ATDD sigue el mismo ciclo Red-Green-Refactor que TDD, por lo que en esta primera
iteración hemos sentado las expectativas tanto de un primer comportamiento del
sistema como de su propia interfaz para operar, sin tener aún nada de código de
producción implementado. Si estáis acostumbradas a trabajar con UTDD, es posible
que este primer test os parezca <em>demasiado grande</em>. Y es que con ATDD el <strong>ciclo
de feedback</strong> es mucho más largo.</p>
<h2>Añadiendo nuevos comportamientos</h2>
<p>Con el test anterior en verde, ya dispondríamos de una versión 0.1.0 de nuestro
Juego de la Vida 🙂 Un CLI que, a partir de un fichero de entrada, sería capaz
de evolucionar el tablero detectando aquellas células que sufran de despoblación
y guardando el resultado en el fichero de salida indicado.</p>
<p>Pero para implementar el Juego de la Vida de manera completa, hay que tener en
cuenta también otros escenarios. El enfoque que apliqué para ello fue ir creando
un nuevo test para cada nuevo comportamiento. Así pues, tras implementar el
soporte para despoblación, el siguiente en la lista era el escenario de
sobrepoblación.</p>
<p>Con esa prueba también en verde, tendríamos una nueva versión 0.2.0 del sistema
lista para desplegar; esta vez, soportando ya un nuevo escenario. Este mismo
flujo se utilizaría para implementar el resto de reglas.</p>
<blockquote>
<p>Cada nuevo test define un nuevo comportamiento de alto nivel en el sistema. Al
resolverlo, nuestro software debería estar listo para ser desplegado.</p>
</blockquote>
<h2>ATDD y productividad</h2>
<p>Seguramente, aplicar ATDD tampoco me hubiese ayudado a terminar de implementar
el Juego de la Vida en los 45 minutos que duran las sesiones de un coderetreat
🙃, pero sí creo que me habría permitido acercarme mucho más que si hubiese
intentado solucionar el sistema siguiendo una estrategia <em>bottom-up</em>.</p>
<p>Trabajar con tests de aceptación me ayudó a ganar foco y programar rápidamente
una solución que los pusiese en verde. Sentir que con cada prueba disfrutas de
un sistema desplegable (aunque su implementación no sea perfecta a nivel de
diseño) me parece un gran <em>boost</em> de productividad. Con 4 pruebas, tienes las
reglas de negocio del Juego de la Vida cubiertas y puedes empezar a aplicar
<em>refactoring</em> para extraer comportamientos a nuevas entidades de manera muy
confiable (los test de aceptación te aseguran que el sistema funciona punto a
punto -y esto, cuando sueles trabajar con muchos pequeños tests unitarios, está
muy bien).</p>
<h2>ATDD y UTDD</h2>
<p>El Juego de la Vida es un problema sencillo, que prácticamente se resuelve con
unas pocas líneas de código. En sistemas más sofisticados, donde estemos
implementando funcionalidad más compleja, es muy habitual mezclar ambos ciclos
para disfrutar de las ventajas de ambos enfoques (lo más habitual es que
trabajemos con código <em>legacy</em>, donde aplicar UTDD es <em>sencillo</em> al tener muchas
entidades de dominio ya modeladas en nuestro sistema).</p>
<p>Juntar ambas estrategias termina generando un <em>ciclo de ciclos</em>, donde el test
de aceptación está en rojo mientras que vamos aplicando ciclos de UTDD para
tratar de ponerlo en verde (y terminar de implementar ese nuevo comportamiento
de alto nivel en el sistema).</p>
<h2>Contenido relacionado</h2>
<p>Si os habéis quedado con ganas de investigar un poco más, el libro
<a href="https://www.amazon.es/Growing-Object-Oriented-Software-Addison-Wesley-Signature-ebook/dp/B002TIOYVW">Growing Object-Oriented Software, Guided by Tests</a>
cubre muy bien (y en profundidad) esta manera de trabajar y resolver los
problemas. Además, he publicado en
<a href="https://github.com/sergioalvz/practice/tree/master/game-of-life-atdd">GitHub</a>
la implementación que utilicé para practicar con este enfoque mientras resolvía
el Juego de la Vida.</p>
<p>La estrategias comentadas en este artículo también se representan en la
literatura a través de los conceptos de <strong>Inside Out</strong> y <strong>Outside In</strong> (que se
cubren en detalle en
<a href="https://8thlight.com/blog/georgina-mcfadyen/2016/06/27/inside-out-tdd-vs-outside-in.html">este artículo</a>).</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[🔗 Quarterlinks #1: Q3 2019]]></title>
        <id>https://codecoolture.com/notes/quarterlinks-q3-2019</id>
        <link href="https://codecoolture.com/notes/quarterlinks-q3-2019"/>
        <updated>2019-10-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Scrum, XP, workshops, software delivery...]]></summary>
        <content type="html"><![CDATA[<h1>Quarterlinks #1: Q3 2019</h1>
<h2>📚 Libros</h2>
<p>Durante estos meses he tenido <em>mucho</em> viaje. Muchas horas de tren (a Madrid,
cinco horitas por trayecto...) y alguna escapada en avión para disfrutar de las
vacaciones de verano 🙂, así que el número de libros ha sido superior al que
acostumbro (aunque bien es cierto que un par de ellos ya los había leído
anteriormente).</p>
<p>Como veréis, esta vez son libros más cercanos a negocio que a la práctica de
desarrollo de software en sí:</p>
<ul>
<li><a href="https://www.infoq.com/minibooks/scrum-xp-from-the-trenches-2/"><strong>Scrum and XP from the Trenches (2nd Edition)</strong></a>:
importante que sea la segunda edición, ya que contiene <em>cortes</em> del autor 8
años después de la primera edición. Me ha gustado el enfoque pragmático del
libro. Con muchos accionables.</li>
<li><a href="https://www.amazon.es/First-90-Days-Updated-Expanded/dp/1422188612"><strong>The First 90 Days</strong></a>:
si te encuentras en un momento de transición (cambio de puesto y/o empresa)
estoy seguro de que podrás sacar algo positivo de este libro. Tienes 90 días
para empezar a conseguir tus primeras victorias y encajar en el engranaje de
la empresa, ¿por dónde empezarías?</li>
<li><a href="https://www.amazon.es/Extreme-Programming-Explained-Embrace-Embracing/dp/0321278658"><strong>Extreme Programming Explained: Embrace Change</strong></a>:
poco que decir... cualquier persona que haya trabajado en entornos <em>Agile</em> ha
sido expuesta, de alguna manera, a las prácticas de Extreme Programming. Se
lee muy bien y sigue aplicando 100% al contexto actual.</li>
<li><a href="https://www.bracketcreative.co.uk/book-effective-workshops/"><strong>Effective Workshops</strong></a>:
siento mucho interés por la cultura de <em>workshops</em> (en general, pero
especialmente aplicado en empresas) y es una habilidad que me gustaría
entrenar. El libro está pensado para ayudarte en tu camino como
host/facilitadora, desde los preámbulos del evento hasta qué hacer una vez ha
terminado. Eso sí, ¡no esperes encontrar ejemplos de ejercicios concretos!</li>
</ul>
<h2>🎬 Charlas</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=vGCowJY5QCQ"><strong>Deliveritis Aguda</strong></a> por
<a href="https://twitter.com/buenosvinos">@buenosvinos</a>: en líneas generales, creo que
la manera de entender el desarrollo de software por parte de Carlos está muy
alineada con mi propia visión y, aunque es muy difícil condensar tanta
información en tan pocos minutos, se exponen de manera clara los <em>pain points</em>
más habituales en el proceso de entrega de software junto con estrategias
eficaces para tratar de mitigarlos. Me quedo con ganas de conocer (más en
profundidad) sus opiniones sobre cómo integrar los procesos de QA dentro del
equipo de desarrollo.</li>
</ul>
<h2>💻 Blogposts</h2>
<ul>
<li><a href="https://ronjeffries.com/articles/019-01ff/no-software/"><strong>No Software: No Agile, No Scrum</strong></a></li>
<li><a href="https://broadcast.listennotes.com/the-boring-technology-behind-listen-notes-56697c2e347b"><strong>The boring technology behind a one-person Internet company</strong></a>:
siempre me parecen súper interesantes este tipo de artículos donde se
desgranan parte de los <em>internals</em> de un proyecto. Me ayuda a coger
perspectiva pudiendo comparar mi experiencia con la de otras personas.</li>
<li><a href="https://charity.wtf/2019/09/08/reasons-not-to-be-a-manager/"><strong>17 Reasons not to be a Manager</strong></a></li>
</ul>
<h2>🎱 Bola extra: Una serie de televisión</h2>
<ul>
<li><a href="https://www.filmaffinity.com/es/film696304.html"><strong>Escape at Dannemora</strong></a>: la
vi casi por casualidad (no recuerdo que se hablase demasiado de ella) pero la
verdad es que me ha encantado; el trío protagonista está muy bien desarrollado
y el ritmo de la serie a mí me ha tenido bastante atrapado (<em>disclaimer</em>: me
gusta que se tomen su tiempo en contar la historia).</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Desacoplando la entrega de software de los sistemas de control de versiones]]></title>
        <id>https://codecoolture.com/blog/decoupling-vcs-from-software-delivery</id>
        <link href="https://codecoolture.com/blog/decoupling-vcs-from-software-delivery"/>
        <updated>2019-06-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Como una extensión más de la ley de Conway, es muy habitual encontrarse con proyectos donde la estrategia de branching del sistema de control de versiones está fuertemente relacionada con la estrategia de entrega de software.]]></summary>
        <content type="html"><![CDATA[<h1>Desacoplando la entrega de software de los sistemas de control de versiones</h1>
<p>Como una extensión más de la
<a href="https://es.wikipedia.org/wiki/Ley_de_Conway">ley de Conway</a>, es muy habitual
encontrarse con proyectos donde la estrategia de <em>branching</em> del sistema de
control de versiones está fuertemente relacionada con la estrategia de entrega
de software. Esta relación entre ambos mundos puede parecer conveniente (por
ejemplo: utilizar una rama para representar el código <em>vivo</em> en producción o
<em>staging</em>, congelar los cambios que van a desplegarse en una rama <code>release/*</code>,
etc.) pero, con el paso del tiempo, puede traer consigo efectos
contraproducentes:</p>
<ul>
<li><strong>Viola el principio de responsabilidad única</strong>. Si algo nos queda claro sobre
el <em>Single Reponsability Principle</em> es que cada abstracción sólo debe tener
<em>una única razón para cambiar</em> (en palabras de Robert C. Martin). Si cambios
en los procesos de entrega de software (flujos de resolución de <em>hotfixes</em>,
nuevos entornos) implican cambios en la estructura de nuestro repositorio (o
cambios en la manera de interactuar con él), los límites entre ambos contextos
no están bien establecidos.</li>
<li><strong>Todo se vuelve innecesariamente complejo</strong>. Aún con flujos muy populares
como <code>git-flow</code> (y herramientas muy sofisticadas a su alrededor, construidas
como una capa de abstracción sobre <code>git</code>), se <em>hackea</em> el sistema de control
de versiones para dejar de ser una herramienta de <em>tracking</em> y colaboración
por un sistema de despliegue y configuración.</li>
<li><strong>Resta flexibilidad</strong>. Si es el sistema de control de versiones el encargado
de determinar qué funcionalidades se van a liberar al final de una iteración,
se pueden dar situaciones en las que una rama se quede <em>congelada</em> por
contener funcionalidad defectuosa que inevitablemente contamina al resto de
cambios de esa misma rama, bloqueando la entrega de nueva funcionalidad.</li>
</ul>
<p><img src="/static/articles/decoupling-vcs-from-software-delivery/git-flow.jpg" alt="Imagen de un repositorio que utiliza git-flow" title="Este repositorio utiliza el sistema de control de versiones como una herramienta de entrega de software para la próxima iteración (aplicando un flujo similar a git-flow)"></p>
<p>Para aliviar los problemas anteriores, una solución pasa por mover la
responsabilidad de decidir qué funcionalidades están disponibles en cada entorno
desde el sistema de control de versiones a la propia base de código. Es decir,
decidir programáticamente si una funcionalidad está habilitada o no en función
de en qué entorno se está ejecutando la aplicación.</p>
<p>Una representación habitual de este principio es a través del uso de
<a href="https://featureflags.io">Feature Flags</a>, que no dejan de ser, conceptualmente,
bloques condicionales que se sitúan en algún punto de nuestra base de código y
deciden si un camino de ejecución debe evaluarse o no.</p>
<p>Con esta estrategia, únicamente necesitaríamos una rama <code>master</code> donde fusionar
las <em>feature branches</em> de funcionalidades terminadas y una configuración de
<em>feature flags</em> que defina los entornos en los que estarían disponibles. Por
ejemplo: habilitar la funcionalidad únicamente en entornos de <em>staging</em> para
realizar pruebas de rendimiento, labores de <em>quality assurance</em>, etc. La
resolución de hotfixes, se podría realizar igualmente sobre la rama <code>master</code>,
pues es esta la que siempre se despliega y define qué funcionalidades estarían
disponibles en cada momento y para cada entorno.</p>
<p><img src="/static/articles/decoupling-vcs-from-software-delivery/with-feature-flags.jpg" alt="Imagen de un repositorio con una única rama master y múltiples feature branches" title="En este ejemplo, el repositorio es agnóstico de la capa de entrega de software, que estará gestionada por la propia base de código mediante el uso de feature toggles."></p>
<p>Siguiendo esta dirección, también se obtendrían beneficios adicionales como, por
ejemplo, poder realizar <em>merges</em> de manera mucho más recurrente (al estar el
entorno de producción siempre protegido a través de <em>feature flags</em>). Esto
podría derivar, a su vez, en procesos de <em>code review</em> con un número menor de
cambios y ciclos de <em>feedback</em> más cortos, siempre que lo combinemos con
técnicas como <em>continuous integration</em> y <em>continuous delivery</em>.</p>
<h2>Otras lecturas relacionadas</h2>
<ul>
<li><a href="https://www.thoughtworks.com/radar/techniques/decoupling-deployment-from-release">Decoupling Deployment from Release - ThoughtWorks’ Technology Radar</a></li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[.dotfiles]]></title>
        <id>https://codecoolture.com/notes/dotfiles</id>
        <link href="https://codecoolture.com/notes/dotfiles"/>
        <updated>2019-05-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Una manera rápida y sencilla de almacenar y sincronizar tus configuraciones]]></summary>
        <content type="html"><![CDATA[<h1>.dotfiles</h1>
<p>Muchas de las herramientas que utilizamos a diario almacenan su configuración
utilizando ficheros denominados <em>dotfiles</em>, (llamados así por su esquema de
nombrado, empezando habitualmente por un <em>punto</em>: <code>.bashrc</code>, <code>.zshrc</code>).</p>
<p>Al tratarse de ficheros en texto plano, es muy sencillo poder almacenarlos en un
sistema de control de versiones y poder reutilizarlos (y sincronizarlos) desde
diferentes equipos.</p>
<p>En Internet ya hay muchos ejemplos de <a href="https://dotfiles.github.io/"><em>dotfiles</em></a>
que pueden servir de referencia (los de
<a href="https://github.com/jessfraz/dotfiles">Jess Frazelle</a> son espectaculares) pero,
al final, es normal que cada persona tenga su propia configuración con detalles
que le hacen ser más productivo o productiva.</p>
<p>Alguna de las estrategias más populares para poder instalar <em>dotfiles</em> es hacer
uso de <a href="https://en.wikipedia.org/wiki/Symbolic_link"><em>symlinks</em></a> y requerir el
menor número de dependencias posible (precisamente, uno de los casos de uso más
habituales es utilizarlos para replicar las dependencias y configuraciones
existentes en otro sistema).</p>
<p>En mi caso, <a href="https://github.com/sergioalvz/.dotfiles">mis <em>dotfiles</em></a> tienen
como únicas dependencias <code>curl</code> y <code>make</code> (disponibles tras una instalación
<em>limpia</em> de macOS), que se utilizan para instalar <code>homebrew</code> y, a través de un
fichero <code>Brewfile</code>, instalar automáticamente el software con el que trabajo
habitualmente 🚀</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[📚 A Philosophy of Software Design]]></title>
        <id>https://codecoolture.com/notes/a-philosophy-of-software-design</id>
        <link href="https://codecoolture.com/notes/a-philosophy-of-software-design"/>
        <updated>2019-04-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Un libro sobre diseño de software con un enfoque práctico y alejado de dogmatismos]]></summary>
        <content type="html"><![CDATA[<h1>A Philosophy of Software Design</h1>
<p>Durante las últimas semanas he estado leyendo este maravilloso libro escrito por
John Ousterhout y me gustaría compartir algunas conclusiones que he podido
extraer tras su lectura.</p>
<p>Lo primero, es que el libro me ha parecido un contrapunto muy interesante a
<a href="https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882"><em>Clean Code</em></a>.
Básicamente, ambos presentan estrategias para reducir la complejidad en el
diseño, desarrollo y mantenimiento de software (y la complejidad es un término
sobre el que se discute largo y tendido en
<a href="https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201"><em>A Philosophy of Software Design</em></a>)
pero lo hacen, bajo mi punto de vista, desde dos ópticas diferentes.</p>
<p>Robert C. Martin (y mucha de la literatura que hay por ahí fuera) pone el foco
especialmente en <strong>reglas</strong> y <strong>principios</strong>: tamaño de las entidades
(¡funciones de menos de 10 líneas!), el número de responsabilidades de una
abstracción, código sobre documentación, evitar duplicidades, etc. Sin embargo,
en <em>A Philosophy of Software Design</em> nos encontramos un par de capítulos
dedicados en exclusiva al “arte” de escribir buenos comentarios y a las ventajas
de invertir tiempo en expresar, a través de los mismos, aspectos relacionados
con el diseño de software que son prácticamente imposibles de describir
utilizando únicamente código (por ejemplo, el conocimiento del dominio que nos
lleva a aplicar ciertos patrones o arquitecturas, <em>workarounds</em> para lidiar con
<em>known issues</em>, etc).</p>
<p>De todos, el capítulo 10: <em>Define Errors Out Of Existence</em>, me ha parecido una
delicia, y creo que introduce conceptos muy interesantes para lidiar con los
casos esquina y errores de cualquier aplicación.</p>
<p>Del mismo modo, algunos pasajes hablando sobre la ventaja de definir
abstracciones “profundas” (<em>deep</em>) en lugar de “planas” (<em>shallow</em>) ilustran
bastante bien los problemas de llevar técnicas de <em>Clean Code</em> al extremo, sin
aplicar un buen criterio.</p>
<p>Creo que la lectura de este libro me ha servido para adoptar un enfoque más
pragmático a la hora de escribir código, alejado de dogmatismos y poniendo el
foco en lo que realmente importa, tratar de reducir al máximo la complejidad de
nuestras soluciones (lo que implícitamente nos llevará también a la aplicación
de buenas prácticas de diseño).</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Taller de Introducción a TDD en AsturiasHacking]]></title>
        <id>https://codecoolture.com/notes/tdd-workshop-asturias-hacking</id>
        <link href="https://codecoolture.com/notes/tdd-workshop-asturias-hacking"/>
        <updated>2019-04-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Breve reflexión sobre el primer taller de introducción a TDD en AsturiasHacking]]></summary>
        <content type="html"><![CDATA[<h1>Introducción a TDD en AsturiasHacking</h1>
<p>Los pasados días
<a href="https://www.meetup.com/AsturiasHacking/events/258852355/">4 y 5 de abril impartí mi primer taller de introducción a TDD</a>
en AsturiasHacking. Después de varios años (co-)organizando esta comunidad,
tenía claro que el tema levantaba cierto interés entre los participantes, que
siempre intentaban algún tipo de aproximación cuando realizamos actividades
prácticas (como el <a href="https://www.coderetreat.org/">Global Day of Coderetreat</a>).</p>
<p>Mi objetivo para el taller era introducir <em>test-driven development</em> desde una
perspetiva nada dogmática, basada en mi experiencia y donde quedara evidente que
se trata de otra herramienta más, útil especialmente de cara a diseñar software
y <strong>poco efectiva</strong> de cara a realizar labores exhaustivas de <em>quality
assurance</em>.</p>
<p>La manera de organizar el taller se dividió en dos tardes, con dos horas de
duración cada sesión. Durante el primer día realizamos una introducción teórica
a la metodología: cuáles son sus &quot;normas&quot; y beneficios. Para después dedicar un
rato a programar en parejas para poder aplicar los conceptos aprendidos.</p>
<p>El segundo día, sin embargo, lo aprovechamos para discutir diferentes
estrategias para enfrentarnos a código <em>legacy</em> y cómo relacionar nuestro código
con el resto de colaboradores de un sistema ya en producción. Para ello,
introdujimos el concepto de <em>test doubles</em>, con sus diferentes tipos y
propósitos, para terminar con una parte práctica donde los participantes debían
enfrentarse a un código sin pruebas, con un diseño muy acoplado y sobre el que
realizar una pequeña extensión de su funcionalidad.</p>
<p>El feedback sobre la sesión fue muy positivo. Por ejemplo, las siguientes citas
ilustran bastante bien las conclusiones que salieron en el <em>closing circle</em>:</p>
<blockquote>
<p>He aprendido, más bien descubierto, una nueva forma de afrontar o aproximarme
a la creación de código nuevo.</p>
</blockquote>
<blockquote>
<p>Me ha sorprendido la forma real de usar TDD ya que sí creía que era únicamente
[hacer] tests.</p>
</blockquote>
<blockquote>
<p>Me ha sorprendido como trabajar en pequeños pasos ayuda a centrarte en el
problema.</p>
</blockquote>
<p>En este enlace os dejo
<a href="http://bit.ly/2U6e5fo">un documento con todos los recursos y bibliografía</a>
utilizados durante la sesión.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Code Smell: React.MultipleRender]]></title>
        <id>https://codecoolture.com/blog/react-multiple-render</id>
        <link href="https://codecoolture.com/blog/react-multiple-render"/>
        <updated>2019-02-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Varios métodos de instancia especializados en construir una parte concreta de la UI de un componente]]></summary>
        <content type="html"><![CDATA[<h1>React: MultipleRender</h1>
<p>El síntoma más claro de este <em>code smell</em> es la aparición de varios métodos de
instancia tipo <code>render</code> especializados en construir una parte de la UI de un
componente React. Suele aparecer especialmente en componentes complejos (o de
gran tamaño, como una página) cuando diferentes partes de la interfaz precisan
de alguna comprobación o cálculo extra que afecte a su representación.</p>
<pre><code class="language-tsx">export class Blog extends React.Component&lt;{ articles: Article[] }&gt; {
  public render() {
    return (
      &lt;&gt;
        {this.renderHeader()}

        {this.renderArticles()}
      &lt;/&gt;
    );
  }

  private renderHeader() {
    const {
      articles: { length: numberOfArticles },
    } = this.props;

    if (numberOfArticles === 0) {
      return (
        &lt;header&gt;
          &lt;p&gt;No articles 😯&lt;/p&gt;
        &lt;/header&gt;
      );
    }

    return (
      &lt;header&gt;
        &lt;p&gt;Yay! {numberOfArticles} articles 🎉&lt;/p&gt;
      &lt;/header&gt;
    );
  }

  private renderArticles() {
    return this.props.articles.map((article) =&gt; {
      return (
        &lt;section&gt;
          &lt;h1&gt;
            &lt;a href={article.url}&gt;{article.title}&lt;/a&gt;
          &lt;/h1&gt;
        &lt;/section&gt;
      );
    });
  }
}
</code></pre>
<p>En el caso anterior, vemos que la representación de la cabecera de la página
varía en función del número de artículos que se vayan a mostrar. Del mismo modo
que la lógica para pintar la colección de artículos está encapsulada en su
propio método de instancia.</p>
<p>Con echar un simple vistazo al método <code>render</code>, ya vemos con claridad cuáles son
las verdaderas responsabilidades de nuestra página: definir un <em>layout</em> que
muestre una cabecera y una colección de artículos.</p>
<p>¿Es, por tanto, responsabilidad de la página conocer los <em>internals</em> de la
cabecera y la lógica necesaria para pintar la colección de artículos? No. Este
componente contiene más de una responsabilidad y no cumple con el
<a href="https://en.wikipedia.org/wiki/Single_responsibility_principle">Principio de Responsabilidad Única</a>.</p>
<p>Para mejorar nuestro diseño, bastaría con definir dos nuevos componentes que
encapsulen la lógica necesaria para pintar ambas partes. Con este enfoque,
ganaríamos cierta capacidad para reutilizar esos componentes en otros lugares de
nuestra interfaz (aunque no es condición necesaria para crear un nuevo
componente) a la vez que reducimos la complejidad del componente padre, que no
necesita ya llevar consigo toda la lógica de las diferentes partes que la
conforman.</p>
<p>Además, si seguís un enfoque de integración y entrega continua, veréis que es
mucho más sencillo <a href="/blog/branch-by-abstraction-react">aplicar <em>feature flags</em></a>
sobre estos pequeños componentes de vuestra interfaz en lugar de en mitad de
componentes grandes y complejos, donde se estarían mezclando responsabilidades y
requisitos de distintas partes de la aplicación.</p>
<pre><code class="language-tsx">import { Articles } from &quot;./components/Articles&quot;;
import { Header } from &quot;./components/Header&quot;;

export function Blog(props: { articles: Article[] }) {
  return (
    &lt;&gt;
      &lt;Header {...props} /&gt;

      &lt;Articles {...props} /&gt;
    &lt;/&gt;
  );
}
</code></pre>
<p>Este <em>code smell</em> está relacionado con otros de propósito general (no
relacionados directamente con React) como
<a href="https://sourcemaking.com/refactoring/smells/large-class"><em>Large Class</em></a> y
técnicas de <em>refactoring</em> como
<a href="https://refactoring.guru/extract-class">Extract Class</a>.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[📚 The Nature of Software Development]]></title>
        <id>https://codecoolture.com/notes/the-nature-of-software-development</id>
        <link href="https://codecoolture.com/notes/the-nature-of-software-development"/>
        <updated>2019-01-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Un libro muy recomendable para empresas de software que quieran entregar valor de manera continua]]></summary>
        <content type="html"><![CDATA[<h1>The Nature of Software Development</h1>
<blockquote>
<p>[...] If you’ve been involved in software development, you too have probably
often felt that all this should be simple, but somehow it gets all
complicated.</p>
<p>— <cite>Ron Jeffries</cite></p>
</blockquote>
<p>Llevaba unos cuantos meses con ganas de poder leer el libro <em>The Nature of
Software Development</em> de Ron Jeffries y, por fin, este enero, he dedicado unas
cuantas horas a poder estudiarlo, disfrutarlo y compartirlo con varias personas
del equipo y colegas de profesión.</p>
<p>Para quien no le conozca,
<a href="https://en.wikipedia.org/wiki/Ron_Jeffries">Ron Jeffries</a> es uno de los
creadores de <em>Extreme Programming</em>, firmante del
<a href="http://agilemanifesto.org/">manifiesto Agile</a> y un profesional con dilatada
experiencia en el desarrollo de software. Un breve vistazo al índice de
contenidos o al resumen de la contraportarda ya es suficiente para entender que
el libro, aunque no mencione explícitamente niguna metodología concreta (más
allá del <em>Natural Way</em> del propio Jeffries), va a ofrecer una lectura amena y un
tanto filosófica sobre el desarrollo de software desde una óptica Agile. En lo
personal, encontré la visión del libro muy alineada con mi propio entendimiento
sobre cómo se deberían desarrollar productos y proyectos digitales.</p>
<p>A través de sus páginas, Jeffries no sólo habla del proceso de implementación
(del que, realmente, apenas menciona más que la búsqueda constante de la
excelencia técnica y los beneficios de aplicar <em>Refactoring</em> de manera regular),
sino que gran parte del libro está centrado en la própia definición de <em>valor</em>
(«lo que necesitas», en palabras del autor) y cómo se puede identificar y
alcanzar lo más rápido posible a través de la construcción de equipos de alto
rendimiento que tengan maestría en técnicas de entrega continua de valor,
<em>planning</em> y <em>slicing</em> de funcionalidades y capacidad para ejecutar y entregar
productos donde la calidad sea una máxima no negociable.</p>
<p>Como imagináis, construir un equipo de estas características requiere de
perfiles multidisciplinares donde personas de negocio y desarrollo trabajen codo
con codo compartiendo una filosofía común.</p>
<p>Sin duda, si trabajáis en una empresa de software (a cualquier nivel), este se
trata de un libro imprescindible.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Code Smell: JavaScript.NakedCode]]></title>
        <id>https://codecoolture.com/blog/javascript-naked-code</id>
        <link href="https://codecoolture.com/blog/javascript-naked-code"/>
        <updated>2019-01-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[NakedCode es un posible code smell que consiste en escribir y ejecutar código directamente en el cuerpo de un módulo]]></summary>
        <content type="html"><![CDATA[<h1>JavaScript: NakedCode</h1>
<blockquote>
<p>Código que se escribe y, por tanto se ejecuta, sin estar encapsulado en ningún
bloque o procedimiento (como por ejemplo una función o una clase).</p>
</blockquote>
<p>En JavaScript, sufrimos de una relación de amor-odio con el contexto de
ejecución goblal. Hasta la aparición de los módulos en la especificación de ES6+
la manera más habitual de gestionar dependencias en nuestra aplicación era a
través de la variable global <code>window</code>, accesible desde cualquier punto de
nuestro programa.</p>
<p>Con los módulos, llegó una manera de gestionar esas dependencias de manera
explícita y favorecer técnicas como
<a href="https://github.com/rollup/rollup#tree-shaking">tree shaking</a> para mejorar el
rendimiento de nuestras aplicaciones. Mientras que, a su vez, ganamos también
cierta capacidad para encapsular nuestro código y evitar que se ejecutase en el
contexto global de la aplicación, junto al resto de código de otros ficheros.</p>
<p>Sin embargo, sigue siendo habitual encontrar este tipo de
<a href="https://martinfowler.com/bliki/CodeSmell.html">code smell</a> gracias a lo
sencillo de codificar directamente en el cuerpo de módulos ECMAScript:</p>
<pre><code class="language-js">const repository = {};

export function addTodo(todo) {
  if (repository[todo.id]) {
    return;
  }

  repository[todo.id] = todo;
}
</code></pre>
<p>Aunque escribir código directamente en el cuerpo de un módulo tiene sus casos de
uso, tiene efectos laterales que pueden ser <strong>no</strong> evidentes:</p>
<ul>
<li>El código del módulo (sin encapsular) es ejecutado por el intérprete la
primera vez que se importa, por lo que perdemos la habilidad de controlar
cuándo evaluar un fragmento de código para, por ejemplo, establecer un
escenario de ejecución determinado en nuestras pruebas.</li>
<li>En el ejemplo anterior, la variable <code>repository</code> es un objeto <em>global</em> (aunque
únicamente accesible desde el propio cuerpo del módulo) que dificulta
enormemente la capacidad de probar el código de manera unitaria, ya que hay
que gestionar el estado de un variable sobre la que no tenemos acceso.</li>
<li>Podemos incurrir en problemas de rendimiento (<em>memory leaks</em>), al disponer de
una serie de variables globales sobre las que el recolector de basura no puede
actuar en caso de no ser necesarias (siempre mantendrán -al menos- una
referencia).</li>
</ul>
<p>¿Cómo podríamos mejorar el caso anterior? Envolviendo el cuerpo del módulo en
una función <code>createRepository</code> que nos devuelva el control sobre el contexto de
ejecución del repositorio.</p>
<pre><code class="language-js">export function createRepository(todos = {}) {
  const repository = { ...todos };

  return {
    addTodo(todo) {
      if (repository[todo.id]) {
        return;
      }

      repository[todo.id] = todo;
    },
  };
}
</code></pre>
<p>A pesar de los problemas anteriores, existen escenarios donde realmente sí
queramos ejecutar código en el cuerpo del módulo para poder beneficiarnos del
hecho de ser una suerte de
<a href="https://en.wikipedia.org/wiki/Singleton_pattern"><em>Singleton</em></a>:</p>
<ul>
<li>Fichero <code>index</code> donde inicializar dependencias globales de la aplicación.</li>
</ul>
<p>Cabe recordar que un <em>code smell</em> no significa que algo esté <em>mal</em>. Simplemente
se refiere a un patrón que <em>puede</em> (esto es importante) conllevar consigo males
de diseño. En este caso, a no ser que sea plenamente consciente de los efectos
laterales que conlleva, evito utilizar <em>naked code</em> en el cuerpo de mis módulos
JavaScript.</p>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Branch By Abstraction en Componentes React]]></title>
        <id>https://codecoolture.com/blog/branch-by-abstraction-react</id>
        <link href="https://codecoolture.com/blog/branch-by-abstraction-react"/>
        <updated>2019-01-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Una sencilla estrategia para implementar técnicas de integración continua en React utilizando Branch by Abstraction y Feature Flags.]]></summary>
        <content type="html"><![CDATA[<h1>Branch by Abstraction en Componentes React</h1>
<p>En ocasiones, nos vemos en la situación de tener que actualizar varios
componentes de nuestra interfaz de usuario para ajustarlos a nuevas directrices
de diseño. Otras veces, necesitamos reemplazar su implementación para hacer
frente a nuevos requisitos de negocio. Si el número de cambios es lo
suficientemente alto, es posible que no se puedan realizar de manera atómica (o
tengan que ser sincronizados con eventos fuera del control del equipo de
desarrollo como, por ejemplo, la publicación de una nueva imagen de marca) a la
vez que necesitamos continuar entregando valor en forma de nuevas
funcionalidades, corrigiendo defectos o aplicando alguna que otra mejora.</p>
<p>En este artículo vamos a hablar sobre una estrategia que nos permita obtener un
flujo de integración continua evitando, por tanto, mantener los cambios en
nuestros componentes en una rama independiente en el sistema de control de
versiones durante el transcurso de su desarrollo.</p>
<p>¿Cómo lo conseguiremos? Haciendo uso de dos técnicas muy habituales en equipos
que trabajan con prácticas como <em>continuous integration</em> o <em>continuous
delivery</em>: <a href="http://featureflags.io/">Feature Flags</a> (o Feature Toggles si
<a href="https://martinfowler.com/bliki/FeatureToggle.html">leéis a Martin Fowler</a>) y
<a href="https://martinfowler.com/bliki/BranchByAbstraction.html">Branch By Abstraction</a>.</p>
<p>Ambas estrategias nos permitirán fusionar código de manera regular sobre la rama
principal, aún con funcionalidades parcialmente terminadas, evitando así
mantener ramas en paralelo que podrían estar días (o semanas) sin integrarse con
el trabajo realizado por el resto del equipo.</p>
<blockquote>
<p>Las feature flags son, conceptualmente, bloques condicionales que permiten
habilitar o deshabilitar una funcionalidad (o un camino de ejecución) en base
a un conjunto de condiciones (como pueden ser: el entorno de ejecución, el
perfil del usuario o un porcentaje de tráfico)</p>
</blockquote>
<p>Pongamos como ejemplo que, en nuestra aplicación, llevamos ya un tiempo
utilizando <code>&lt;AwesomeCalendar /&gt;</code> (un componente de terceros) como <em>widget</em> de
calendario. En los puntos donde es necesario mostrar un calendario, importamos
el componente y lo insertamos en el <em>layout</em> de la página.</p>
<pre><code class="language-tsx">import React from &quot;react&quot;;

import { AwesomeCalendar } from &quot;awesome-calendar&quot;;

function Page() {
  return (
    &lt;Page&gt;
      &lt;Header /&gt;

      &lt;Body&gt;
        &lt;AwesomeCalendar date={new Date(2018, 6, 21)} /&gt;
      &lt;/Body&gt;
    &lt;/Page&gt;
  );
}
</code></pre>
<p>Debido a una serie de requisitos, tenemos que crear un nuevo componente para
mostrar un calendario que sustituya a <code>AwesomeCalendar</code> y le añada un <em>extra</em> de
funcionalidad para dar cabida a nuevas historias de usuario. El desarrollo del
componente se extenderá durante varias semanas.</p>
<p>El primer paso para poder integrar nuestro componente de manera continua es
asegurar que somos capaces de controlar cuándo y cómo se utiliza para poder
aislar a los consumidores de <code>AwesomeCalendar</code> de los cambios en el mismo. Para
ello, vamos a empezar creando una nueva <em>abstracción</em> <code>Calendar</code> que pasará a
ser utilizada por el resto de componentes y mantendrá la misma interfaz que
ofrecía <code>AwesomeCalendar</code>:</p>
<pre><code class="language-tsx">import React from &quot;react&quot;;

import { AwesomeCalendar } from &quot;awesome-calendar&quot;;

export function Calendar({ date }: { date: Date }) {
  return &lt;AwesomeCalendar date={date} /&gt;;
}
</code></pre>
<p>Como vemos, la manera de consumir este nuevo componente sería muy parecida a la
versión anterior:</p>
<pre><code class="language-tsx">import React from &quot;react&quot;;

import { Calendar } from &quot;../components&quot;;

function Page() {
  return (
    &lt;Page&gt;
      &lt;Header /&gt;

      &lt;Body&gt;
        &lt;Calendar date={new Date(2018, 6, 21)} /&gt;
      &lt;/Body&gt;
    &lt;/Page&gt;
  );
}
</code></pre>
<blockquote>
<p>En este punto, ya podríamos fusionar nuestros cambios con la rama de código
principal para que el resto de trabajo en curso pueda ir haciendo uso de
nuestro (no tan) <em>nuevo</em> componente.</p>
</blockquote>
<p>A continuación, vamos a crear una implementación muy sencilla de nuestro propio
calendario, que empezará apoyándose en una implementación nativa de <code>datetime</code>
pero respetando la interfaz original del componente <code>AwesomeCalendar</code>:</p>
<pre><code class="language-tsx">import React from &quot;react&quot;;

export function NewCalendar({ date }: { date: Date }) {
  const value = /* implementation details */;

  return &lt;input type=&quot;datetime-local&quot; value={value} /&gt;;
}
</code></pre>
<p>Una vez hemos eliminado la responsabilidad de elegir qué calendario utilizar de
los consumidores del componente, podemos utilizar <em>feature flags</em> para
determinar qué calendario mostrar en cada momento.</p>
<p>En este caso, vamos a permitir que cualquier entorno que <strong>no sea producción</strong>
utilice siempre nuestro propio calendario, con el objetivo de obtener <em>feedback</em>
sobre su experiencia de uso a medida que avanzamos en su desarrollo:</p>
<pre><code class="language-ts">export function isNewCalendarEnabled() {
  return process.env.NODE_ENV !== &quot;production&quot;;
}
</code></pre>
<blockquote>
<p>Este caso, representamos la feature flag con una simple función que comprueba
el entorno de ejecución actual, pero existen
<a href="https://github.com/Unleash/unleash">sistemas más sofisticados</a> para gestionar
el estado de los <em>toggles</em> en nuestra aplicación.</p>
</blockquote>
<p>Ahora, nuestra nueva abstracción <code>Calendar</code> (que hace las veces de factoría)
puede hacer uso de esta función para determinar qué componente de calendario
utilizar, manteniendo al resto de consumidores aislados de toda complejidad:</p>
<pre><code class="language-tsx">import React from &quot;react&quot;;

import { AwesomeCalendar } from &quot;awesome-calendar&quot;;

import { NewCalendar } from &quot;./components&quot;;

import { isNewCalendarEnabled } from &quot;../features&quot;;

export function Calendar(props: { date: Date }) {
  return isNewCalendarEnabled() ? (
    &lt;NewCalendar {...props} /&gt;
  ) : (
    &lt;AwesomeCalendar {...props} /&gt;
  );
}
</code></pre>
<p>A partir de este momento, todas las pantallas de nuestra interfaz de usuario que
necesiten de un calendario, utilizarán la abstracción <code>Calendar</code> y será esta
misma abstracción la que se encargará de utilizar la implementación concreta del
calendario que corresponda en función del entorno de ejecución.</p>
<p>Como vemos, aplicar técnicas como <em>branch by abstraction</em> y <em>feature flags</em> nos
permite alcanzar un flujo de integración (y entrega) continua en nuestros
componentes aportándonos beneficios cómo:</p>
<ul>
<li>Minimizar la superficie de cambios a fusionar cuando integramos trabajo en
curso</li>
<li>Tomar el control sobre cuándo se ejercita un camino de ejecución y poder
habilitarlo y deshabilitarlo en base a una serie de condiciones</li>
<li>Dotar a los equipos de negocio de visibilidad sobre el trabajo en curso en
tareas de larga duración (sin sacrificar ninguna de las premisas anteriores)</li>
</ul>
]]></content>
        <author>
            <name>Sergio Álvarez</name>
            <email>hola@codecoolture.com</email>
            <uri>https://codecoolture.com/about</uri>
        </author>
    </entry>
</feed>